diff --git a/source/graphics/ModelDef.cpp b/source/graphics/ModelDef.cpp index abf8adecab..9fc4eae5f4 100644 --- a/source/graphics/ModelDef.cpp +++ b/source/graphics/ModelDef.cpp @@ -38,7 +38,7 @@ CVector3D CModelDef::SkinNormal(const SModelVertex& vtx, // inverse of the transpose. Unfortunately inverses are slow. // If a matrix is orthogonal, M * M^T = I and so the inverse of the transpose // is the original matrix. But that's not entirely relevant here, because - // the cone matrices include translation components and so they're not + // the bone matrices include translation components and so they're not // orthogonal. // But that's okay because we have // M = T * R diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index ec0a30cd3f..d7461d806d 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -366,6 +366,7 @@ CRenderer::CRenderer() m_Options.m_FancyWater = false; m_ShadowZBias = 0.02f; + m_ShadowMapSize = 0; for (uint i=0;iEffectiveWidth = 0; m->EffectiveHeight = 0; m->UseDepthTexture = false; - m->DepthTextureBits = 16; + m->DepthTextureBits = 24; } @@ -274,12 +274,23 @@ void ShadowMapInternals::CreateTexture() pglGenFramebuffersEXT(1, &Framebuffer); } - // get shadow map size as next power of two up from view width and height - Width = g_Renderer.GetWidth(); - Width = std::min(RoundUpToPowerOf2(Width), (int)ogl_max_tex_size); - Height = g_Renderer.GetHeight(); - Height = std::min(RoundUpToPowerOf2(Height), (int)ogl_max_tex_size); + if (g_Renderer.m_ShadowMapSize != 0) + { + // non-default option to override the size + Width = Height = g_Renderer.m_ShadowMapSize; + } + else + { + // get shadow map size as next power of two up from view width and height + Width = RoundUpToPowerOf2(g_Renderer.GetWidth()); + Height = RoundUpToPowerOf2(g_Renderer.GetHeight()); + } + // Clamp to the maximum texture size + Width = std::min(Width, (int)ogl_max_tex_size); + Height = std::min(Height, (int)ogl_max_tex_size); + // If we're using a framebuffer object, the whole texture is available; otherwise + // we're limited to the part of the screen buffer that is actually visible if (Framebuffer) { EffectiveWidth = Width; @@ -287,15 +298,16 @@ void ShadowMapInternals::CreateTexture() } else { - EffectiveWidth = std::min(Width, (u32)g_Renderer.GetWidth()); - EffectiveHeight = std::min(Height, (u32)g_Renderer.GetHeight()); + EffectiveWidth = std::min(Width, g_Renderer.GetWidth()); + EffectiveHeight = std::min(Height, g_Renderer.GetHeight()); } const char* formatname = "LUMINANCE"; if (UseDepthTexture) { - switch(DepthTextureBits) { + switch(DepthTextureBits) + { case 16: formatname = "DEPTH_COMPONENT16"; break; case 24: formatname = "DEPTH_COMPONENT24"; break; case 32: formatname = "DEPTH_COMPONENT32"; break; @@ -303,20 +315,21 @@ void ShadowMapInternals::CreateTexture() } } - LOG(NORMAL, LOG_CATEGORY, "Creating shadow texture (size %ix%i) (format = %s)%s", + LOG(NORMAL, LOG_CATEGORY, "Creating shadow texture (size %dx%d) (format = %s)%s", Width, Height, formatname, Framebuffer ? " (using EXT_framebuffer_object)" : ""); // create texture object glGenTextures(1, &Texture); g_Renderer.BindTexture(0, Texture); - u32 size = Width*Height; + int size = Width*Height; if (UseDepthTexture) { GLenum format; - switch(DepthTextureBits) { + switch(DepthTextureBits) + { case 16: format = GL_DEPTH_COMPONENT16; break; case 24: format = GL_DEPTH_COMPONENT24; break; case 32: format = GL_DEPTH_COMPONENT32; break; @@ -324,9 +337,9 @@ void ShadowMapInternals::CreateTexture() } float* buf = new float[size]; - for(uint i = 0; i < size; i++) buf[i] = 1.0; - glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, - GL_DEPTH_COMPONENT, GL_FLOAT, buf); + for (int i = 0; i < size; i++) + buf[i] = 1.0; + glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buf); delete[] buf; glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); @@ -335,9 +348,10 @@ void ShadowMapInternals::CreateTexture() } else { - u32* buf=new u32[size]; - for (uint i=0;iTexture); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight()); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m->EffectiveWidth, m->EffectiveHeight); } } diff --git a/source/renderer/TransparencyRenderer.cpp b/source/renderer/TransparencyRenderer.cpp index ff5b0d64f2..0982740dc9 100644 --- a/source/renderer/TransparencyRenderer.cpp +++ b/source/renderer/TransparencyRenderer.cpp @@ -268,14 +268,28 @@ void PolygonSortModelRenderer::DestroyModelData(CModel* UNUSED(model), void* dat // Prepare for one rendering pass -void PolygonSortModelRenderer::BeginPass(uint streamflags, const CMatrix3D* UNUSED(texturematrix)) +void PolygonSortModelRenderer::BeginPass(uint streamflags, const CMatrix3D* texturematrix) { - debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_COLOR|STREAM_UV0))); + debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_COLOR|STREAM_UV0|STREAM_TEXGENTOUV1))); glEnableClientState(GL_VERTEX_ARRAY); if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY); + if (streamflags & STREAM_TEXGENTOUV1) + { + pglActiveTextureARB(GL_TEXTURE1); + pglClientActiveTextureARB(GL_TEXTURE1); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(&texturematrix->_11); + glMatrixMode(GL_MODELVIEW); + + pglActiveTextureARB(GL_TEXTURE0); + pglClientActiveTextureARB(GL_TEXTURE0); + } } @@ -284,6 +298,20 @@ void PolygonSortModelRenderer::EndPass(uint streamflags) { if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY); if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY); + if (streamflags & STREAM_TEXGENTOUV1) + { + pglActiveTextureARB(GL_TEXTURE1); + pglClientActiveTextureARB(GL_TEXTURE1); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + + pglActiveTextureARB(GL_TEXTURE0); + pglClientActiveTextureARB(GL_TEXTURE0); + } glDisableClientState(GL_VERTEX_ARRAY); } @@ -319,6 +347,14 @@ void PolygonSortModelRenderer::RenderModel(uint streamflags, CModel* model, void glVertexPointer(3, GL_FLOAT, stride, base + psmdl->m_Position.offset); if (streamflags & STREAM_COLOR) glColorPointer(3, psmdl->m_Color.type, stride, base + psmdl->m_Color.offset); + if (streamflags & STREAM_TEXGENTOUV1) + { + pglClientActiveTextureARB(GL_TEXTURE1); + pglActiveTextureARB(GL_TEXTURE1); + glTexCoordPointer(3, GL_FLOAT, stride, base + psmdl->m_Position.offset); + pglClientActiveTextureARB(GL_TEXTURE0); + pglActiveTextureARB(GL_TEXTURE0); + } // render the lot size_t numFaces = mdef->GetNumFaces(); diff --git a/source/simulation/Projectile.cpp b/source/simulation/Projectile.cpp index 99873c6966..a1e090c13f 100644 --- a/source/simulation/Projectile.cpp +++ b/source/simulation/Projectile.cpp @@ -243,10 +243,15 @@ CProjectileManager::CProjectileManager() CProjectileManager::~CProjectileManager() { - while( m_Projectiles.size() ) - delete( m_Projectiles[0] ); + DeleteAll(); } +void CProjectileManager::DeleteAll() +{ + while( !( m_Projectiles.empty() ) ) + delete( m_Projectiles[0] ); // removes itself from m_Projectiles +} + CProjectile* CProjectileManager::AddProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript ) { CProjectile* p = new CProjectile( Actor, Position, Target, Speed, Originator, ImpactScript, MissScript ); @@ -261,13 +266,12 @@ void CProjectileManager::DeleteProjectile( CProjectile* p ) void CProjectileManager::UpdateAll( size_t timestep ) { - uint i; - for( i = 0; i < m_Projectiles.size(); i++ ) + m_LastTurnLength = timestep; + for( size_t i = 0; i < m_Projectiles.size(); ) if( !( m_Projectiles[i]->Update( timestep ) ) ) - { - delete( m_Projectiles[i] ); - i--; - } + delete( m_Projectiles[i] ); // removes itself from m_Projectiles + else + i++; } void CProjectileManager::InterpolateAll( double relativeOffset ) diff --git a/source/simulation/Projectile.h b/source/simulation/Projectile.h index ef5adec6b7..0783f52182 100644 --- a/source/simulation/Projectile.h +++ b/source/simulation/Projectile.h @@ -86,6 +86,8 @@ public: CProjectileManager(); ~CProjectileManager(); + void DeleteAll(); + void UpdateAll( size_t timestep ); void InterpolateAll( double frametime ); diff --git a/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.cpp b/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.cpp index ed5f8acc1a..519888ef30 100644 --- a/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.cpp +++ b/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.cpp @@ -21,6 +21,15 @@ Please complain if I forget to do those things. #ifdef _MSC_VER # pragma warning(disable: 4100 4505 4510 4610) +// Doesn't have inttypes.h, so cheat before including the ffmpeg headers +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; #endif #include "ffmpeg/avformat.h" @@ -32,6 +41,7 @@ struct VideoEncoderImpl int framerate; int bitrate; float duration; + int width, height; AVStream *video_st; AVFormatContext *oc; @@ -69,31 +79,19 @@ struct VideoEncoderImpl c->codec_id = (CodecID)codec_id; c->codec_type = CODEC_TYPE_VIDEO; - c->bit_rate = bitrate*1000; - c->width = 640; - c->height = 480; +// c->bit_rate = bitrate*1000; + // TODO: support compressed formats, using qscale + + c->width = width; + c->height = height; c->time_base.den = framerate; c->time_base.num = 1; - c->pix_fmt = PIX_FMT_YUV420P; +// c->pix_fmt = PIX_FMT_YUV420P; + c->pix_fmt = PIX_FMT_RGBA32; - // TODO: these compression parameters aren't necessarily any good - - c->mb_decision = FF_MB_DECISION_RD; - c->gop_size = 12; - c->max_b_frames = 2; - c->b_frame_strategy = 1; - c->dia_size = 4; - - c->me_cmp = c->me_sub_cmp = FF_CMP_SAD; - c->mb_cmp = FF_CMP_SSE; - - c->last_predictor_count = 3; - - c->flags |= CODEC_FLAG_4MV | CODEC_FLAG_QP_RD; - - if(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp")) + if (oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return st; @@ -147,7 +145,7 @@ struct VideoEncoderImpl as long as they're aligned enough for the architecture, and they're freed appropriately (such as using av_free for buffers allocated with av_malloc) */ - video_outbuf_size = bitrate*1000/framerate * 8; + video_outbuf_size = c->width * c->height * 4; video_outbuf = (uint8_t*)av_malloc(video_outbuf_size); } @@ -215,7 +213,7 @@ struct VideoEncoderImpl if (oc->oformat->flags & AVFMT_RAWPICTURE) { /* raw video case. The API will change slightly in the near - futur for that */ + future for that */ AVPacket pkt; av_init_packet(&pkt); @@ -233,7 +231,10 @@ struct VideoEncoderImpl AVPacket pkt; av_init_packet(&pkt); - pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base); + if (c->coded_frame->pts == AV_NOPTS_VALUE) + pkt.pts = AV_NOPTS_VALUE; + else + pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base); if(c->coded_frame->key_frame) pkt.flags |= PKT_FLAG_KEY; pkt.stream_index= st->index; @@ -276,13 +277,15 @@ void log(void* v, int i, const char* format, va_list ap) wxLogDebug(L"[%d] %hs", i, buf); } -VideoEncoder::VideoEncoder(const wxString& filenameStr, int framerate, int bitrate, float duration) +VideoEncoder::VideoEncoder(const wxString& filenameStr, int framerate, int bitrate, float duration, int width, int height) : m(new VideoEncoderImpl) { wxCharBuffer filename = filenameStr.ToAscii(); m->framerate = framerate; m->bitrate = bitrate; m->duration = duration; + m->width = width; + m->height = height; /* initialize libavcodec, and register all codecs and formats */ av_register_all(); @@ -292,7 +295,7 @@ VideoEncoder::VideoEncoder(const wxString& filenameStr, int framerate, int bitra /* auto detect the output format from the name. default is mpeg. */ m->fmt = guess_format(NULL, filename, NULL); if (!m->fmt) { - printf("Could not deduce output format from file extension: using MPEG.\n"); + fprintf(stderr, "Could not deduce output format from file extension: using MPEG.\n"); m->fmt = guess_format("mpeg", NULL, NULL); } if (!m->fmt) { @@ -312,10 +315,11 @@ VideoEncoder::VideoEncoder(const wxString& filenameStr, int framerate, int bitra /* add the audio and video streams using the default format codecs and initialize the codecs */ - m->video_st = NULL; - if (m->fmt->video_codec != CODEC_ID_NONE) { - m->video_st = m->add_video_stream(m->oc, m->fmt->video_codec); - } +// m->video_st = NULL; +// if (m->fmt->video_codec != CODEC_ID_NONE) { +// m->video_st = m->add_video_stream(m->oc, m->fmt->video_codec); +// } + m->video_st = m->add_video_stream(m->oc, CODEC_ID_FFV1); /* set the output parameters (must be done even if no parameters). */ @@ -373,7 +377,7 @@ VideoEncoder::~VideoEncoder() av_write_trailer(m->oc); /* free the streams */ - for(int i = 0; i < m->oc->nb_streams; i++) { + for(unsigned int i = 0; i < m->oc->nb_streams; i++) { av_freep(&m->oc->streams[i]->codec); av_freep(&m->oc->streams[i]); } diff --git a/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.h b/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.h index 7217b36f38..acd53d89b0 100644 --- a/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.h +++ b/source/tools/atlas/AtlasUI/General/VideoRecorder/FFmpeg.h @@ -6,7 +6,7 @@ struct VideoEncoderImpl; class VideoEncoder { public: - VideoEncoder(const wxString& filename, int framerate, int bitrate, float duration); + VideoEncoder(const wxString& filename, int framerate, int bitrate, float duration, int width, int height); void Frame(const unsigned char* buffer); ~VideoEncoder(); diff --git a/source/tools/atlas/AtlasUI/General/VideoRecorder/VideoRecorder.cpp b/source/tools/atlas/AtlasUI/General/VideoRecorder/VideoRecorder.cpp index 7db5d07b6e..b1831bbb6f 100644 --- a/source/tools/atlas/AtlasUI/General/VideoRecorder/VideoRecorder.cpp +++ b/source/tools/atlas/AtlasUI/General/VideoRecorder/VideoRecorder.cpp @@ -178,9 +178,12 @@ void VideoRecorder::RecordCinematic(wxWindow* window, const wxString& trackName, wxStopWatch sw; - VideoEncoder venc (dlg.m_Filename, dlg.m_Framerate, dlg.m_Bitrate, duration); +// int w = 320, h = 240; + int w = 640, h = 480; - qCinemaRecord qry(trackName.c_str(), dlg.m_Framerate, duration, Callback(&callback, (void*)&venc)); + VideoEncoder venc (dlg.m_Filename, dlg.m_Framerate, dlg.m_Bitrate, duration, w, h); + + qCinemaRecord qry(trackName.c_str(), dlg.m_Framerate, duration, w, h, Callback(&callback, (void*)&venc)); qry.Post(); wxLogMessage(_("Finished recording (took %.1f seconds)\n"), sw.Time()/1000.f); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp index 7679943a87..98284c585a 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp @@ -276,6 +276,7 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame) EVT_MENU(ID_Open, ScenarioEditor::OnOpen) EVT_MENU(ID_Save, ScenarioEditor::OnSave) EVT_MENU(ID_SaveAs, ScenarioEditor::OnSaveAs) + EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, ScenarioEditor::OnMRUFile) EVT_MENU(ID_Quit, ScenarioEditor::OnQuit) EVT_MENU(wxID_UNDO, ScenarioEditor::OnUndo) @@ -296,6 +297,7 @@ AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc; ScenarioEditor::ScenarioEditor(wxWindow* parent) : wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, wxSize(1024, 768)) +, m_FileHistory(_T("Scenario Editor")) { // Global application initialisation: @@ -324,8 +326,8 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) menuFile->Append(ID_SaveAs, _("Save &As...")); menuFile->AppendSeparator();//----------- menuFile->Append(ID_Quit, _("E&xit")); -// m_FileHistory.UseMenu(menuFile);//------- -// m_FileHistory.AddFilesToMenu(); + m_FileHistory.UseMenu(menuFile);//------- + m_FileHistory.AddFilesToMenu(); } // m_menuItem_Save = menuFile->FindItem(ID_Save); // remember this item, to let it be greyed out @@ -352,6 +354,8 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) menuMisc->Append(ID_JavaScript, _("&JS console")); } + m_FileHistory.Load(*wxConfigBase::Get()); + m_SectionLayout.SetWindow(this); @@ -362,10 +366,10 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) // (button label; tooltip text; image; internal tool name; section to switch to) toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""), _T("")); - toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"), _T("ObjectSidebar")); - toolbar->AddToolButton(_("Elevation"), _("Alter terrain elevation"), _T("alterelevation.png"), _T("AlterElevation"), _T("TerrainSidebar")); - toolbar->AddToolButton(_("Flatten"), _("Flatten terrain elevation"), _T("flattenelevation.png"), _T("FlattenElevation"), _T("TerrainSidebar")); - toolbar->AddToolButton(_("Paint Terrain"), _("Paint terrain texture"), _T("paintterrain.png"), _T("PaintTerrain"), _T("TerrainSidebar")); + toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"), _T("")/*_T("ObjectSidebar")*/); + toolbar->AddToolButton(_("Elevation"), _("Alter terrain elevation"), _T("alterelevation.png"), _T("AlterElevation"), _T("")/*_T("TerrainSidebar")*/); + toolbar->AddToolButton(_("Flatten"), _("Flatten terrain elevation"), _T("flattenelevation.png"), _T("FlattenElevation"), _T("")/*_T("TerrainSidebar")*/); + toolbar->AddToolButton(_("Paint Terrain"), _("Paint terrain texture"), _T("paintterrain.png"), _T("PaintTerrain"), _T("")/*_T("TerrainSidebar")*/); toolbar->Realize(); SetToolBar(toolbar); @@ -442,6 +446,8 @@ void ScenarioEditor::OnClose(wxCloseEvent&) { SetCurrentTool(_T("")); + m_FileHistory.Save(*wxConfigBase::Get()); + POST_MESSAGE(Shutdown, ()); qExit().Post(); @@ -491,6 +497,30 @@ void ScenarioEditor::OnRedo(wxCommandEvent&) ////////////////////////////////////////////////////////////////////////// +void ScenarioEditor::OpenFile(const wxString& name) +{ + wxBusyInfo busy(_("Loading map")); + wxBusyCursor busyc; + + // TODO: Work when the map is not in .../maps/scenarios/ + std::wstring map = name.c_str(); + + // Deactivate tools, so they don't carry forwards into the new CWorld + // and crash. + SetCurrentTool(_T("")); + // TODO: clear the undo buffer, etc + + POST_MESSAGE(LoadMap, (map)); + + SetOpenFilename(name); + + // Wait for it to load, while the wxBusyInfo is telling the user that we're doing that + qPing qry; + qry.Post(); + + // TODO: Make this a non-undoable command +} + // TODO (eventually): replace all this file-handling stuff with the Workspace Editor void ScenarioEditor::OnOpen(wxCommandEvent& WXUNUSED(event)) @@ -503,26 +533,7 @@ void ScenarioEditor::OnOpen(wxCommandEvent& WXUNUSED(event)) wxString cwd = wxFileName::GetCwd(); if (dlg.ShowModal() == wxID_OK) - { - wxBusyInfo busy(_("Loading map")); - wxBusyCursor busyc; - - // TODO: Work when the map is not in .../maps/scenarios/ - std::wstring map = dlg.GetFilename().c_str(); - - // Deactivate tools, so they don't carry forwards into the new CWorld - // and crash. - SetCurrentTool(_T("")); - // TODO: clear the undo buffer, etc - - POST_MESSAGE(LoadMap, (map)); - - SetOpenFilename(dlg.GetFilename()); - - // Wait for it to load, while the wxBusyInfo is telling the user that we're doing that - qPing qry; - qry.Post(); - } + OpenFile(dlg.GetFilename()); wxCHECK_RET(cwd == wxFileName::GetCwd(), _T("cwd changed")); // paranoia - MSDN says OFN_NOCHANGEDIR (used when we don't give wxCHANGE_DIR) @@ -531,6 +542,13 @@ void ScenarioEditor::OnOpen(wxCommandEvent& WXUNUSED(event)) // TODO: Make this a non-undoable command } +void ScenarioEditor::OnMRUFile(wxCommandEvent& event) +{ + wxString file (m_FileHistory.GetHistoryFile(event.GetId() - wxID_FILE1)); + if (file.Len()) + OpenFile(file); +} + void ScenarioEditor::OnSave(wxCommandEvent& event) { if (m_OpenFilename.IsEmpty()) @@ -584,6 +602,9 @@ void ScenarioEditor::SetOpenFilename(const wxString& filename) (filename.IsEmpty() ? wxString(_("(untitled)")) : filename).c_str())); m_OpenFilename = filename; + + if (! filename.IsEmpty()) + m_FileHistory.AddFileToHistory(filename); } ////////////////////////////////////////////////////////////////////////// diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h index 380d67dda6..c247640b6f 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h @@ -2,6 +2,7 @@ #define SCENARIOEDITOR_H__ #include "General/AtlasWindowCommandProc.h" +#include "CustomControls/FileHistory/FileHistory.h" #include "SectionLayout.h" class ScenarioEditor : public wxFrame @@ -16,6 +17,7 @@ public: void OnOpen(wxCommandEvent& event); void OnSave(wxCommandEvent& event); void OnSaveAs(wxCommandEvent& event); + void OnMRUFile(wxCommandEvent& event); void OnQuit(wxCommandEvent& event); void OnUndo(wxCommandEvent& event); @@ -27,6 +29,8 @@ public: void OnMediaPlayer(wxCommandEvent& event); void OnJavaScript(wxCommandEvent& event); + void OpenFile(const wxString& name); + static AtlasWindowCommandProc& GetCommandProc(); static float GetSpeedModifier(); @@ -38,6 +42,7 @@ private: void SetOpenFilename(const wxString& filename); wxString m_OpenFilename; + FileHistory m_FileHistory; DECLARE_EVENT_TABLE(); }; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp index bebdf6a967..4c774f5ca7 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp @@ -15,6 +15,7 @@ enum ID_GenerateRMS, ID_SimPlay, ID_SimFast, + ID_SimSlow, ID_SimPause, ID_SimReset }; @@ -24,8 +25,10 @@ enum SimInactive, SimPlaying, SimPlayingFast, + SimPlayingSlow, SimPaused }; +bool IsPlaying(int s) { return (s == SimPlaying || s == SimPlayingFast || s == SimPlayingSlow); } MapSidebar::MapSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer) : Sidebar(sidebarContainer, bottomBarContainer), m_SimState(SimInactive) @@ -47,6 +50,7 @@ MapSidebar::MapSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer) wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Simulation test")); sizer->Add(new wxButton(this, ID_SimPlay, _("Play")), wxSizerFlags().Proportion(1)); sizer->Add(new wxButton(this, ID_SimFast, _("Fast")), wxSizerFlags().Proportion(1)); + sizer->Add(new wxButton(this, ID_SimSlow, _("Slow")), wxSizerFlags().Proportion(1)); sizer->Add(new wxButton(this, ID_SimPause, _("Pause")), wxSizerFlags().Proportion(1)); sizer->Add(new wxButton(this, ID_SimReset, _("Reset")), wxSizerFlags().Proportion(1)); UpdateSimButtons(); @@ -85,9 +89,13 @@ void MapSidebar::UpdateSimButtons() wxCHECK(button, ); button->Enable(m_SimState != SimPlayingFast); + button = wxDynamicCast(FindWindow(ID_SimSlow), wxButton); + wxCHECK(button, ); + button->Enable(m_SimState != SimPlayingSlow); + button = wxDynamicCast(FindWindow(ID_SimPause), wxButton); wxCHECK(button, ); - button->Enable(m_SimState == SimPlaying || m_SimState == SimPlayingFast); + button->Enable(IsPlaying(m_SimState)); button = wxDynamicCast(FindWindow(ID_SimReset), wxButton); wxCHECK(button, ); @@ -103,6 +111,11 @@ void MapSidebar::OnSimPlay(wxCommandEvent& event) speed = 8.f; newState = SimPlayingFast; } + else if (event.GetId() == ID_SimSlow) + { + speed = 0.125f; + newState = SimPlayingSlow; + } if (m_SimState == SimInactive) { @@ -120,7 +133,7 @@ void MapSidebar::OnSimPlay(wxCommandEvent& event) void MapSidebar::OnSimPause(wxCommandEvent& WXUNUSED(event)) { - if (m_SimState == SimPlaying || m_SimState == SimPlayingFast) + if (IsPlaying(m_SimState)) { POST_MESSAGE(SimPlay, (0.f)); m_SimState = SimPaused; @@ -130,7 +143,7 @@ void MapSidebar::OnSimPause(wxCommandEvent& WXUNUSED(event)) void MapSidebar::OnSimReset(wxCommandEvent& WXUNUSED(event)) { - if (m_SimState == SimPlaying || m_SimState == SimPlayingFast) + if (IsPlaying(m_SimState)) { POST_MESSAGE(SimPlay, (0.f)); POST_MESSAGE(SimStateRestore, (L"default")); @@ -149,6 +162,7 @@ BEGIN_EVENT_TABLE(MapSidebar, Sidebar) EVT_BUTTON(ID_GenerateRMS, MapSidebar::GenerateRMS) EVT_BUTTON(ID_SimPlay, MapSidebar::OnSimPlay) EVT_BUTTON(ID_SimFast, MapSidebar::OnSimPlay) + EVT_BUTTON(ID_SimSlow, MapSidebar::OnSimPlay) EVT_BUTTON(ID_SimPause, MapSidebar::OnSimPause) EVT_BUTTON(ID_SimReset, MapSidebar::OnSimReset) END_EVENT_TABLE(); diff --git a/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp index b2cd2156e1..59536ce2ae 100644 --- a/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/MiscHandlers.cpp @@ -34,7 +34,7 @@ QUERYHANDLER(CinemaRecord) CCinemaManager* manager = g_Game->GetView()->GetCinema(); manager->SetCurrentTrack(*msg->track, false, false, false); - const int w = 640, h = 480; + const int w = msg->width, h = msg->height; { g_Renderer.Resize(w, h); @@ -44,6 +44,7 @@ QUERYHANDLER(CinemaRecord) } unsigned char* img = new unsigned char [w*h*3]; + unsigned char* temp = new unsigned char[w*3]; int num_frames = msg->framerate * msg->duration; @@ -63,13 +64,14 @@ QUERYHANDLER(CinemaRecord) glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, img); // Swap the rows around, else the image will be upside down - char temp[w*3]; +//* // TODO: BGR24 output doesn't need flipping, YUV420 and RGBA32 do for (int y = 0; y < h/2; ++y) { memcpy2(temp, &img[y*w*3], w*3); memcpy2(&img[y*w*3], &img[(h-1-y)*w*3], w*3); memcpy2(&img[(h-1-y)*w*3], temp, w*3); } +//*/ // Call the user-supplied function with this data, so they can // store it as a video @@ -84,6 +86,7 @@ QUERYHANDLER(CinemaRecord) // TODO: delete the saved state now that we don't need it any more delete[] img; + delete[] temp; // Restore viewport { diff --git a/source/tools/atlas/GameInterface/Messages.h b/source/tools/atlas/GameInterface/Messages.h index 3d8ef60cdd..60cba32624 100644 --- a/source/tools/atlas/GameInterface/Messages.h +++ b/source/tools/atlas/GameInterface/Messages.h @@ -109,6 +109,8 @@ QUERY(CinemaRecord, ((std::wstring, track)) ((int, framerate)) ((float, duration)) + ((int, width)) + ((int, height)) ((Callback, cb)) , ); diff --git a/source/tools/atlas/GameInterface/View.cpp b/source/tools/atlas/GameInterface/View.cpp index 463923e200..da61c15c03 100644 --- a/source/tools/atlas/GameInterface/View.cpp +++ b/source/tools/atlas/GameInterface/View.cpp @@ -24,6 +24,7 @@ #include "simulation/EntityManager.h" #include "simulation/EntityTemplate.h" #include "simulation/EntityTemplateCollection.h" +#include "simulation/Projectile.h" #include "simulation/Simulation.h" extern void (*Atlas_GLSwapBuffers)(void* context); @@ -306,6 +307,7 @@ void ViewGame::RestoreState(const std::wstring& label) CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager(); // delete all existing entities + g_Game->GetWorld()->GetProjectileManager().DeleteAll(); g_EntityManager.deleteAll(); if (! simState->onlyEntities) diff --git a/source/tools/entgraph/entgraph.pl b/source/tools/entgraph/entgraph.pl index 9d5d83d816..8348de4007 100644 --- a/source/tools/entgraph/entgraph.pl +++ b/source/tools/entgraph/entgraph.pl @@ -25,7 +25,7 @@ for my $f (@xml) { $parent = $1 if $data =~ /Parent="(.*?)"/; my ($upgrade, $rank); - $upgrade = $1 if $data =~ /Up.*newentity="(.*?)"/s; + $upgrade = $1 if $data =~ /\s*(.*?)\s*