From 2cd91a56c45a2fe014ffd61c5953466c0d1c7848 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 12 Jan 2013 14:05:54 +0100 Subject: [PATCH] Add support for algo=script overlays --- CMakeLists.txt | 4 +- src/mape/cpp-handles/log-handle.cpp | 59 ++++++++++++++++++++++ src/mape/cpp-handles/log-handle.h | 32 ++++++++++++ src/mape/cpp-handles/mapgen-handle.cpp | 70 +++++++++++++++++++++++--- src/mape/cpp-handles/mapgen-handle.h | 2 +- src/mape/cpp-handles/stub-handle.cpp | 5 ++ src/mape/editview.c | 56 ++++++++++++++++----- src/mape/mapgen.c | 7 +++ src/mape/mapgen.h | 1 + 9 files changed, 215 insertions(+), 21 deletions(-) create mode 100644 src/mape/cpp-handles/log-handle.cpp create mode 100644 src/mape/cpp-handles/log-handle.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e08833f28..423c65fd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,7 +587,6 @@ set(MAPE_BASE_SOURCES src/lib/C4Real.h src/lib/C4Rect.cpp src/lib/C4Rect.h - src/lib/C4SimpleLog.cpp src/lib/Standard.cpp src/lib/Standard.h src/lib/StdBuf.cpp @@ -611,6 +610,7 @@ set(MAPE_BASE_SOURCES src/script/C4AulParse.cpp src/script/C4PropList.cpp src/script/C4PropList.h + src/script/C4Script.cpp src/script/C4ScriptHost.cpp src/script/C4ScriptHost.h src/script/C4StringTable.cpp @@ -628,6 +628,8 @@ set(MAPE_BASE_SOURCES set(MAPE_SOURCES src/mape/cpp-handles/group-handle.h src/mape/cpp-handles/group-handle.cpp + src/mape/cpp-handles/log-handle.h + src/mape/cpp-handles/log-handle.cpp src/mape/cpp-handles/mapgen-handle.h src/mape/cpp-handles/mapgen-handle.cpp src/mape/cpp-handles/material-handle.h diff --git a/src/mape/cpp-handles/log-handle.cpp b/src/mape/cpp-handles/log-handle.cpp new file mode 100644 index 000000000..bc0fc30d6 --- /dev/null +++ b/src/mape/cpp-handles/log-handle.cpp @@ -0,0 +1,59 @@ +/* + * mape - C4 Landscape.txt editor + * + * Copyright (c) 2005-2009 Armin Burgmeier + * + * Portions might be copyrighted by other authors who have contributed + * to OpenClonk. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * See isc_license.txt for full license and disclaimer. + * + * "Clonk" is a registered trademark of Matthes Bender. + * See clonk_trademark_license.txt for full license. + */ + +#include +#include + +// This implements the Log engine function such that the first log message +// is stored and can be retrieved later by the C API. +std::string first_log; +bool Log(const char *msg) +{ + if(first_log.empty()) + first_log = msg; + return true; +} +bool DebugLog(const char *strMessage) { return Log(strMessage); } +bool LogFatal(const char *strMessage) { return Log(strMessage); } + +#define IMPLEMENT_LOGF(func) \ + bool func(const char *msg, ...) { \ + va_list args; va_start(args, msg); \ + StdStrBuf Buf; \ + Buf.FormatV(msg, args); \ + return Log(Buf.getData()); \ + } + +IMPLEMENT_LOGF(DebugLogF) +IMPLEMENT_LOGF(LogF) +IMPLEMENT_LOGF(LogSilentF) + +// C API follows here +extern "C" { + +void c4_log_handle_clear() +{ + first_log.clear(); +} + +const char* c4_log_handle_get_first_log_message() +{ + if(first_log.empty()) return NULL; + return first_log.c_str(); +} + +} // extern "C" diff --git a/src/mape/cpp-handles/log-handle.h b/src/mape/cpp-handles/log-handle.h new file mode 100644 index 000000000..691d6def7 --- /dev/null +++ b/src/mape/cpp-handles/log-handle.h @@ -0,0 +1,32 @@ +/* + * mape - C4 Landscape.txt editor + * + * Copyright (c) 2005-2009 Armin Burgmeier + * + * Portions might be copyrighted by other authors who have contributed + * to OpenClonk. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * See isc_license.txt for full license and disclaimer. + * + * "Clonk" is a registered trademark of Matthes Bender. + * See clonk_trademark_license.txt for full license. + */ + +#ifndef INC_MAPE_C4_LOG_HANDLE_H +#define INC_MAPE_C4_LOG_HANDLE_H + +#include + +G_BEGIN_DECLS + +typedef struct _C4MapgenHandle C4MapgenHandle; + +void c4_log_handle_clear(); +const char* c4_log_handle_get_first_log_message(); + +G_END_DECLS + +#endif /* INC_MAPE_C4_LOG_HANDLE_H */ diff --git a/src/mape/cpp-handles/mapgen-handle.cpp b/src/mape/cpp-handles/mapgen-handle.cpp index 2584c0007..36bafbe07 100644 --- a/src/mape/cpp-handles/mapgen-handle.cpp +++ b/src/mape/cpp-handles/mapgen-handle.cpp @@ -16,15 +16,14 @@ */ #include "C4Include.h" -//#include -//#include -//#include -//#include -//#include #include +#include +#include +#include #include "mape/cpp-handles/material-handle.h" #include "mape/cpp-handles/texture-handle.h" +#include "mape/cpp-handles/log-handle.h" #include "mape/cpp-handles/mapgen-handle.h" #define HANDLE_TO_MATERIAL_MAP(handle) (reinterpret_cast(handle)) @@ -55,7 +54,7 @@ struct _C4MapgenHandle { BYTE* data; }; -C4MapgenHandle* c4_mapgen_handle_new(const char* filename, const char* source, C4MaterialMapHandle* material_map, C4TextureMapHandle* texture_map, unsigned int map_width, unsigned int map_height) +C4MapgenHandle* c4_mapgen_handle_new(const char* filename, const char* source, const char* script_path, C4MaterialMapHandle* material_map, C4TextureMapHandle* texture_map, unsigned int map_width, unsigned int map_height) { try { @@ -79,11 +78,68 @@ C4MapgenHandle* c4_mapgen_handle_new(const char* filename, const char* source, C C4MCMap* map = mapgen.GetMap(NULL); if(!map) throw C4MCParserErr(&parser, "No map definition in source file"); + // Setup the script engine if there is an algo=script overlay in the + // Landscape.txt file if(HasAlgoScript(mapgen.GetMap(NULL))) - throw C4MCParserErr(&parser, "algo=script is not yet supported!"); + { + if(script_path == NULL) + throw C4MCParserErr(&parser, "For algo=script overlays to work, save the file first at the location of the Script.c file"); + gchar* dirname = g_path_get_dirname(script_path); + gchar* basename = g_path_get_basename(script_path); + + C4Group File; + if(!File.Open(dirname)) + { + g_free(dirname); + g_free(basename); + throw C4MCParserErr(&parser, File.GetError()); + } + + // get scripts + File.ResetSearch(); + if(!File.FindNextEntry(basename, (char*)NULL)) + { + g_free(dirname); + g_free(basename); + StdStrBuf error_msg = FormatString("Failed to load '%s': No such file", script_path); + throw C4MCParserErr(&parser, error_msg.getData()); + } + + // load core functions into script engine + InitCoreFunctionMap(&ScriptEngine); + + c4_log_handle_clear(); + GameScript.Load(File, basename, NULL, NULL); + g_free(dirname); + g_free(basename); + + const char* parse_error = c4_log_handle_get_first_log_message(); + if(parse_error) + throw C4MCParserErr(&parser, parse_error); + + // Link script engine (resolve includes/appends, generate code) + c4_log_handle_clear(); + ScriptEngine.Link(&::Definitions); + if(ScriptEngine.warnCnt > 0 || ScriptEngine.errCnt > 0) + throw C4MCParserErr(&parser, c4_log_handle_get_first_log_message()); + // Set name list for globals + ScriptEngine.GlobalNamed.SetNameList(&ScriptEngine.GlobalNamedNames); + } + + c4_log_handle_clear(); int32_t out_width, out_height; BYTE* array = mapgen.RenderBuf(NULL, out_width, out_height); + GameScript.Clear(); + ScriptEngine.Clear(); + + // Don't show any map if there was a script runtime error + const char* runtime_error = c4_log_handle_get_first_log_message(); + if(runtime_error) + { + delete[] array; + throw C4MCParserErr(&parser, runtime_error); + } C4MapgenHandle* handle = new C4MapgenHandle; handle->width = map_width; diff --git a/src/mape/cpp-handles/mapgen-handle.h b/src/mape/cpp-handles/mapgen-handle.h index 63eddb6e8..813970da7 100644 --- a/src/mape/cpp-handles/mapgen-handle.h +++ b/src/mape/cpp-handles/mapgen-handle.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS typedef struct _C4MapgenHandle C4MapgenHandle; -C4MapgenHandle* c4_mapgen_handle_new(const char* filename, const char* source, C4MaterialMapHandle* material_map, C4TextureMapHandle* texture_map, unsigned int map_width, unsigned int map_height); +C4MapgenHandle* c4_mapgen_handle_new(const char* filename, const char* source, const char* script_path, C4MaterialMapHandle* material_map, C4TextureMapHandle* texture_map, unsigned int map_width, unsigned int map_height); void c4_mapgen_handle_free(C4MapgenHandle* mapgen); const unsigned char* c4_mapgen_handle_get_map(C4MapgenHandle* mapgen); diff --git a/src/mape/cpp-handles/stub-handle.cpp b/src/mape/cpp-handles/stub-handle.cpp index 56c5b5cda..638df6da3 100644 --- a/src/mape/cpp-handles/stub-handle.cpp +++ b/src/mape/cpp-handles/stub-handle.cpp @@ -43,6 +43,7 @@ C4Set C4PropListNumbered::PropLists; int32_t C4PropListNumbered::EnumerationIndex = 0; C4StringTable Strings; C4AulScriptEngine ScriptEngine; +C4DefList Definitions; /* These are just stubs used by dead code: */ C4Landscape Landscape; @@ -98,12 +99,16 @@ C4IDListChunk::~C4IDListChunk() {} void C4Def::IncludeDefinition(C4Def*) {} +C4DefList::C4DefList() {} +C4DefList::~C4DefList() {} C4Def* C4DefList::ID2Def(C4ID) {return NULL;} void C4DefList::Draw(C4ID, C4Facet &, bool, int32_t) {} C4Def * C4DefList::GetDef(int) {return 0;} int C4DefList::GetDefCount() {return 0;} void C4DefList::CallEveryDefinition() {} void C4DefList::ResetIncludeDependencies() {} +bool C4DefList::DrawFontImage(const char* szImageTag, C4Facet& rTarget, C4DrawTransform* pTransform) { return false; } +float C4DefList::GetFontImageAspect(const char* szImageTag) { return -1.0f; } C4Landscape::C4Landscape() {} C4Landscape::~C4Landscape() {} diff --git a/src/mape/editview.c b/src/mape/editview.c index b9de07d33..78674f8d3 100644 --- a/src/mape/editview.c +++ b/src/mape/editview.c @@ -30,6 +30,7 @@ typedef struct _ThreadData ThreadData; struct _ThreadData { MapeEditView* view; gchar* source; + gchar* file_path; MapeMaterialMap* mat_map; MapeTextureMap* tex_map; guint map_width; @@ -68,6 +69,7 @@ static void mape_edit_view_cb_update(GtkWidget* widget, } static GdkPixbuf* mape_edit_view_render_map(const gchar* source, + const gchar* file_path, MapeMaterialMap* mat_map, MapeTextureMap* tex_map, guint map_width, @@ -75,6 +77,11 @@ static GdkPixbuf* mape_edit_view_render_map(const gchar* source, GError** error) { GdkPixbuf* pixbuf; + gchar* basename; + gchar* dirname; + gchar* scriptname; + const gchar* filename; + if(mat_map == NULL || tex_map == NULL) { g_set_error( @@ -87,9 +94,26 @@ static GdkPixbuf* mape_edit_view_render_map(const gchar* source, return NULL; } + if(file_path != NULL) + { + basename = g_path_get_basename(file_path); + filename = basename; + + dirname = g_path_get_dirname(file_path); + scriptname = g_build_filename(dirname, "Script.c", NULL); + g_free(dirname); + } + else + { + basename = NULL; + filename = "Landscape.txt"; + scriptname = NULL; + } + pixbuf = mape_mapgen_render( - "Landscape.txt", /* TODO: Use actual filename */ + filename, source, + scriptname, mat_map, tex_map, map_width, @@ -97,6 +121,7 @@ static GdkPixbuf* mape_edit_view_render_map(const gchar* source, error ); + g_free(basename); return pixbuf; } @@ -151,6 +176,7 @@ static gpointer mape_edit_view_thread_entry(gpointer data_) res_buf = mape_edit_view_render_map( data->source, + data->file_path, data->mat_map, data->tex_map, data->map_width, @@ -164,6 +190,7 @@ static gpointer mape_edit_view_thread_entry(gpointer data_) result->error = error; g_free(data->source); + g_free(data->file_path); g_slice_free(ThreadData, data); result->idle_id = g_idle_add_full( @@ -337,6 +364,9 @@ void mape_edit_view_destroy(MapeEditView* view) void mape_edit_view_clear(MapeEditView* view) { + g_free(view->file_path); + view->file_path = NULL; + /* TODO: Undoable action dingsen */ /* (statische mape_edit_view_set_contents-Call?) */ gtk_text_buffer_set_text( @@ -349,9 +379,6 @@ void mape_edit_view_clear(MapeEditView* view) gtk_text_view_get_buffer(GTK_TEXT_VIEW(view->view)), FALSE ); - - g_free(view->file_path); - view->file_path = NULL; } gboolean mape_edit_view_open(MapeEditView* view, @@ -422,6 +449,12 @@ gboolean mape_edit_view_open(MapeEditView* view, view->encoding = "UTF-8"; } + /* TODO: Verify that filename is absolute and make it absolute if + it is not */ + new_path = g_strdup(filename); + g_free(view->file_path); + view->file_path = new_path; + /* TODO: Undoable action dingsen */ /* (statische mape_edit_view_set_contents-Call?) */ gtk_text_buffer_set_text( @@ -436,12 +469,6 @@ gboolean mape_edit_view_open(MapeEditView* view, gtk_text_view_get_buffer(GTK_TEXT_VIEW(view->view)), FALSE ); - - /* TODO: Verify that filename is absolute and make it absolute if - it is not */ - new_path = g_strdup(filename); - g_free(view->file_path); - view->file_path = new_path; return TRUE; } @@ -488,7 +515,11 @@ gboolean mape_edit_view_save(MapeEditView* view, new_path = g_strdup(filename); g_free(view->file_path); view->file_path = new_path; - + + /* Rerender with new file path -- + * different Script.c lookup for algo=script overlays */ + mape_edit_view_reload(view); + return TRUE; } @@ -596,12 +627,13 @@ void mape_edit_view_reload(MapeEditView* edit_view) * thread result handler */ data->view = edit_view; data->source = gtk_text_buffer_get_text(buffer, &begin, &end, TRUE); + data->file_path = g_strdup(edit_view->file_path); /* TODO: We need to ref these so noone can delete them while the thread * uses them. */ data->mat_map = edit_view->pre_view->mat_tex->mat_map, data->tex_map = edit_view->pre_view->mat_tex->tex_map, - + data->map_width = edit_view->map_width; data->map_height = edit_view->map_height; diff --git a/src/mape/mapgen.c b/src/mape/mapgen.c index 3d70858b8..29bc67548 100644 --- a/src/mape/mapgen.c +++ b/src/mape/mapgen.c @@ -104,6 +104,7 @@ static void mape_mapgen_read_color(guint8* dest, * @filename: The filename of the file that is being parsed. This is only used * for display purposes. * @source: The map generator source code for the map to generate. + * @script_path: Path to the script source for algo=script overlays, or %NULL. * @material_map: The material map containing the materials to be used during * map generation. * @texture_map: The texture map containing the textures to be used during map @@ -116,6 +117,10 @@ static void mape_mapgen_read_color(guint8* dest, * The pixel color depends on the texture at the corresponding position and is * determined by the average color of that texture. * + * If the source contains one or more algo=script overlays and @script_path is + * %NULL, an error is generated. Otherwise, the file at @script_path is opened + * and used to look up the relevant script functions. + * * In case an error occurs, for example when the map generator source code is * not valid, @error is set and the function returns %NULL. * @@ -125,6 +130,7 @@ static void mape_mapgen_read_color(guint8* dest, GdkPixbuf* mape_mapgen_render(const gchar* filename, const gchar* source, + const gchar* script_path, MapeMaterialMap* material_map, MapeTextureMap* texture_map, guint width, @@ -148,6 +154,7 @@ mape_mapgen_render(const gchar* filename, handle = c4_mapgen_handle_new( filename, source, + script_path, _mape_material_map_get_handle(material_map), _mape_texture_map_get_handle(texture_map), width, diff --git a/src/mape/mapgen.h b/src/mape/mapgen.h index 23811b3e5..607d35431 100644 --- a/src/mape/mapgen.h +++ b/src/mape/mapgen.h @@ -44,6 +44,7 @@ typedef enum _MapeMapgenError { GdkPixbuf* mape_mapgen_render(const gchar* filename, const gchar* source, + const gchar* script_path, MapeMaterialMap* material_map, MapeTextureMap* texture_map, guint width,