mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-22 01:55:25 -04:00
9d09ad4dd9
* This allows to display texts on screen that use a "bitmap font", generated with softwares like [BMFont](https://www.angelcode.com/products/bmfont/) or [bmGlyph](http://www.bmglyph.com/). * Bitmap fonts allow advanced effects and custom design of each character, with complete control over the appearance of the text. This is useful for making a custom score counter, titles, button labels... * They also render very well in a pixel-perfect, pixel-art or retro-like game. * Finally, these Bitmap Texts are fast and efficient to render on screen: useful for scores or texts that are updated frequently.
199 lines
7.2 KiB
C++
199 lines
7.2 KiB
C++
#include "ObjectJsImplementation.h"
|
|
|
|
#include <GDCore/IDE/Project/ArbitraryResourceWorker.h>
|
|
#include <GDCore/Project/Object.h>
|
|
#include <GDCore/Project/Project.h>
|
|
#include <GDCore/Project/PropertyDescriptor.h>
|
|
#include <GDCore/Serialization/Serializer.h>
|
|
#include <GDCore/Serialization/SerializerElement.h>
|
|
#include <emscripten.h>
|
|
|
|
#include <map>
|
|
|
|
using namespace gd;
|
|
|
|
std::unique_ptr<gd::Object> ObjectJsImplementation::Clone() const {
|
|
ObjectJsImplementation* clone = new ObjectJsImplementation(*this);
|
|
|
|
// Copy the references to the JS implementations of the functions (because we
|
|
// want an object cloned from C++ to retain the functions implemented in JS).
|
|
EM_ASM_INT(
|
|
{
|
|
var clone = Module['wrapPointer']($0, Module['ObjectJsImplementation']);
|
|
var self = Module['wrapPointer']($1, Module['ObjectJsImplementation']);
|
|
clone['getProperties'] = self['getProperties'];
|
|
clone['updateProperty'] = self['updateProperty'];
|
|
clone['getInitialInstanceProperties'] =
|
|
self['getInitialInstanceProperties'];
|
|
clone['updateInitialInstanceProperty'] =
|
|
self['updateInitialInstanceProperty'];
|
|
},
|
|
(int)clone,
|
|
(int)this);
|
|
|
|
return std::unique_ptr<gd::Object>(clone);
|
|
}
|
|
|
|
std::map<gd::String, gd::PropertyDescriptor>
|
|
ObjectJsImplementation::GetProperties() const {
|
|
std::map<gd::String, gd::PropertyDescriptor>* jsCreatedProperties = nullptr;
|
|
std::map<gd::String, gd::PropertyDescriptor> copiedProperties;
|
|
|
|
jsCreatedProperties = (std::map<gd::String, gd::PropertyDescriptor>*)EM_ASM_INT(
|
|
{
|
|
var self = Module['getCache'](Module['ObjectJsImplementation'])[$0];
|
|
if (!self.hasOwnProperty('getProperties'))
|
|
throw 'getProperties is not defined on a ObjectJsImplementation.';
|
|
|
|
var objectContent = JSON.parse(UTF8ToString($1));
|
|
var newProperties = self['getProperties'](objectContent);
|
|
if (!newProperties)
|
|
throw 'getProperties returned nothing in a gd::ObjectJsImplementation.';
|
|
|
|
return getPointer(newProperties);
|
|
},
|
|
(int)this,
|
|
jsonContent.c_str());
|
|
|
|
copiedProperties = *jsCreatedProperties;
|
|
delete jsCreatedProperties;
|
|
return copiedProperties;
|
|
}
|
|
bool ObjectJsImplementation::UpdateProperty(const gd::String& arg0,
|
|
const gd::String& arg1) {
|
|
jsonContent = (const char*)EM_ASM_INT(
|
|
{
|
|
var self = Module['getCache'](Module['ObjectJsImplementation'])[$0];
|
|
if (!self.hasOwnProperty('updateProperty'))
|
|
throw 'updateProperty is not defined on a ObjectJsImplementation.';
|
|
var objectContent = JSON.parse(UTF8ToString($1));
|
|
self['updateProperty'](
|
|
objectContent, UTF8ToString($2), UTF8ToString($3));
|
|
return ensureString(JSON.stringify(objectContent));
|
|
},
|
|
(int)this,
|
|
jsonContent.c_str(),
|
|
arg0.c_str(),
|
|
arg1.c_str());
|
|
|
|
return true;
|
|
}
|
|
|
|
std::map<gd::String, gd::PropertyDescriptor>
|
|
ObjectJsImplementation::GetInitialInstanceProperties(
|
|
const gd::InitialInstance& instance,
|
|
gd::Project& project,
|
|
gd::Layout& scene) {
|
|
std::map<gd::String, gd::PropertyDescriptor>* jsCreatedProperties = nullptr;
|
|
std::map<gd::String, gd::PropertyDescriptor> copiedProperties;
|
|
|
|
jsCreatedProperties = (std::map<gd::String, gd::PropertyDescriptor>*)EM_ASM_INT(
|
|
{
|
|
var self = Module['getCache'](Module['ObjectJsImplementation'])[$0];
|
|
if (!self.hasOwnProperty('getInitialInstanceProperties'))
|
|
throw 'getInitialInstanceProperties is not defined on a ObjectJsImplementation.';
|
|
|
|
var objectContent = JSON.parse(UTF8ToString($1));
|
|
var newProperties = self['getInitialInstanceProperties'](
|
|
objectContent,
|
|
wrapPointer($2, Module['InitialInstance']),
|
|
wrapPointer($3, Module['Project']),
|
|
wrapPointer($4, Module['Layout']));
|
|
if (!newProperties)
|
|
throw 'getInitialInstanceProperties returned nothing in a gd::ObjectJsImplementation.';
|
|
|
|
return getPointer(newProperties);
|
|
},
|
|
(int)this,
|
|
jsonContent.c_str(),
|
|
(int)&instance,
|
|
(int)&project,
|
|
(int)&scene);
|
|
|
|
copiedProperties = *jsCreatedProperties;
|
|
delete jsCreatedProperties;
|
|
return copiedProperties;
|
|
}
|
|
|
|
bool ObjectJsImplementation::UpdateInitialInstanceProperty(
|
|
gd::InitialInstance& instance,
|
|
const gd::String& name,
|
|
const gd::String& value,
|
|
gd::Project& project,
|
|
gd::Layout& scene) {
|
|
return EM_ASM_INT(
|
|
{
|
|
var self = Module['getCache'](Module['ObjectJsImplementation'])[$0];
|
|
if (!self.hasOwnProperty('updateInitialInstanceProperty'))
|
|
throw 'updateInitialInstanceProperty is not defined on a ObjectJsImplementation.';
|
|
var objectContent = JSON.parse(UTF8ToString($1));
|
|
return self['updateInitialInstanceProperty'](
|
|
objectContent,
|
|
wrapPointer($2, Module['InitialInstance']),
|
|
UTF8ToString($3),
|
|
UTF8ToString($4),
|
|
wrapPointer($5, Module['Project']),
|
|
wrapPointer($6, Module['Layout']));
|
|
},
|
|
(int)this,
|
|
jsonContent.c_str(),
|
|
(int)&instance,
|
|
name.c_str(),
|
|
value.c_str(),
|
|
(int)&project,
|
|
(int)&scene);
|
|
}
|
|
|
|
void ObjectJsImplementation::DoSerializeTo(SerializerElement& arg0) const {
|
|
arg0.AddChild("content") = gd::Serializer::FromJSON(jsonContent);
|
|
}
|
|
void ObjectJsImplementation::DoUnserializeFrom(Project& arg0,
|
|
const SerializerElement& arg1) {
|
|
jsonContent = gd::Serializer::ToJSON(arg1.GetChild("content"));
|
|
}
|
|
|
|
void ObjectJsImplementation::__destroy__() { // Useless?
|
|
EM_ASM_INT(
|
|
{
|
|
var self = Module['getCache'](Module['ObjectJsImplementation'])[$0];
|
|
if (!self.hasOwnProperty('__destroy__'))
|
|
throw 'a JSImplementation must implement all functions, you forgot ObjectJsImplementation::__destroy__.';
|
|
self['__destroy__']();
|
|
},
|
|
(int)this);
|
|
}
|
|
|
|
void ObjectJsImplementation::ExposeResources(
|
|
gd::ArbitraryResourceWorker& worker) {
|
|
std::map<gd::String, gd::PropertyDescriptor> properties = GetProperties();
|
|
|
|
for (auto& property : properties) {
|
|
const String& propertyName = property.first;
|
|
const gd::PropertyDescriptor& propertyDescriptor = property.second;
|
|
if (propertyDescriptor.GetType() == "resource") {
|
|
auto& extraInfo = propertyDescriptor.GetExtraInfo();
|
|
const gd::String& resourceType = extraInfo.empty() ? "" : extraInfo[0];
|
|
const gd::String& oldPropertyValue = propertyDescriptor.GetValue();
|
|
|
|
gd::String newPropertyValue = oldPropertyValue;
|
|
if (resourceType == "image") {
|
|
worker.ExposeImage(newPropertyValue);
|
|
} else if (resourceType == "audio") {
|
|
worker.ExposeAudio(newPropertyValue);
|
|
} else if (resourceType == "font") {
|
|
worker.ExposeFont(newPropertyValue);
|
|
} else if (resourceType == "video") {
|
|
// Not supported in gd::ArbitraryResourceWorker
|
|
} else if (resourceType == "json") {
|
|
// Not supported in gd::ArbitraryResourceWorker
|
|
} else if (resourceType == "bitmapFont") {
|
|
worker.ExposeBitmapFont(newPropertyValue);
|
|
}
|
|
|
|
if (newPropertyValue != oldPropertyValue) {
|
|
UpdateProperty(propertyName, newPropertyValue);
|
|
}
|
|
}
|
|
}
|
|
}
|