Merge branch 'master' into block
commit
a1def7e762
|
@ -146,9 +146,7 @@
|
|||
E82E677418EA7972004DBA18 /* VersionInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E85233791839B28C00F40541 /* VersionInfo.cpp */; };
|
||||
E82E677518EA7972004DBA18 /* Thread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8CF03B0178EE300000683D4 /* Thread.cpp */; };
|
||||
E82E677618EA7972004DBA18 /* Semaphore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8CF03CF178EEF80000683D4 /* Semaphore.cpp */; };
|
||||
E82E677718EA7972004DBA18 /* Mutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8CF03D2178EF069000683D4 /* Mutex.cpp */; };
|
||||
E82E677818EA7972004DBA18 /* ILockable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8CF03D5178EF09C000683D4 /* ILockable.cpp */; };
|
||||
E82E677918EA7972004DBA18 /* AutoLocker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8CF03D8178EF165000683D4 /* AutoLocker.cpp */; };
|
||||
E82E677A18EA7972004DBA18 /* IRunnable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8CF03DE178EF4E9000683D4 /* IRunnable.cpp */; };
|
||||
E82E677B18EA7972004DBA18 /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8CF0403178FF776000683D4 /* Exception.cpp */; };
|
||||
E82E677C18EA7972004DBA18 /* DynamicLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8567E5E1792C0FF009D83E0 /* DynamicLibrary.cpp */; };
|
||||
|
@ -273,6 +271,7 @@
|
|||
E8403CA8229061BF00093C3E /* RandomAccessAdaptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8403CA6229061BE00093C3E /* RandomAccessAdaptor.cpp */; };
|
||||
E8403CAB229123CF00093C3E /* PipeStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8403CA9229123CF00093C3E /* PipeStream.cpp */; };
|
||||
E8403CAE2291280800093C3E /* GameMapLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8403CAD2291280700093C3E /* GameMapLoader.cpp */; };
|
||||
E8403CB12299073400093C3E /* VoxelModelLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E8403CB02299073400093C3E /* VoxelModelLoader.cpp */; };
|
||||
E8626EAE1E1009D7003365BF /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E844888617D26699005105D0 /* libcurl.tbd */; };
|
||||
E8626EB61E100EC6003365BF /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E8626EB51E100EC6003365BF /* libfreetype.a */; };
|
||||
E8626EB81E100FB2003365BF /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E8626EB71E100FB2003365BF /* libogg.a */; };
|
||||
|
@ -431,6 +430,8 @@
|
|||
E8403CAA229123CF00093C3E /* PipeStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PipeStream.h; sourceTree = "<group>"; };
|
||||
E8403CAC2291280700093C3E /* GameMapLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameMapLoader.h; sourceTree = "<group>"; };
|
||||
E8403CAD2291280700093C3E /* GameMapLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameMapLoader.cpp; sourceTree = "<group>"; };
|
||||
E8403CAF2299073400093C3E /* VoxelModelLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoxelModelLoader.h; sourceTree = "<group>"; };
|
||||
E8403CB02299073400093C3E /* VoxelModelLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VoxelModelLoader.cpp; sourceTree = "<group>"; };
|
||||
E842888918A3CF6C0060743D /* StartupScreen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StartupScreen.cpp; sourceTree = "<group>"; };
|
||||
E842888A18A3CF6C0060743D /* StartupScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StartupScreen.h; sourceTree = "<group>"; };
|
||||
E842888C18A3D1520060743D /* StartupScreenHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StartupScreenHelper.cpp; sourceTree = "<group>"; };
|
||||
|
@ -790,12 +791,8 @@
|
|||
E8CF03CD178EE95F000683D4 /* Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Math.h; sourceTree = "<group>"; };
|
||||
E8CF03CF178EEF80000683D4 /* Semaphore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Semaphore.cpp; sourceTree = "<group>"; };
|
||||
E8CF03D0178EEF80000683D4 /* Semaphore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Semaphore.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
|
||||
E8CF03D2178EF069000683D4 /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mutex.cpp; sourceTree = "<group>"; };
|
||||
E8CF03D3178EF06A000683D4 /* Mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mutex.h; sourceTree = "<group>"; };
|
||||
E8CF03D5178EF09C000683D4 /* ILockable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ILockable.cpp; sourceTree = "<group>"; };
|
||||
E8CF03D6178EF09C000683D4 /* ILockable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ILockable.h; sourceTree = "<group>"; };
|
||||
E8CF03D8178EF165000683D4 /* AutoLocker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AutoLocker.cpp; sourceTree = "<group>"; };
|
||||
E8CF03D9178EF166000683D4 /* AutoLocker.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = AutoLocker.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
|
||||
E8CF03DE178EF4E9000683D4 /* IRunnable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IRunnable.cpp; sourceTree = "<group>"; };
|
||||
E8CF03DF178EF4E9000683D4 /* IRunnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRunnable.h; sourceTree = "<group>"; };
|
||||
E8CF03E1178EF57E000683D4 /* SDLRunner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SDLRunner.cpp; sourceTree = "<group>"; };
|
||||
|
@ -1820,12 +1817,8 @@
|
|||
E8CF03B1178EE300000683D4 /* Thread.h */,
|
||||
E8CF03CF178EEF80000683D4 /* Semaphore.cpp */,
|
||||
E8CF03D0178EEF80000683D4 /* Semaphore.h */,
|
||||
E8CF03D2178EF069000683D4 /* Mutex.cpp */,
|
||||
E8CF03D3178EF06A000683D4 /* Mutex.h */,
|
||||
E8CF03D5178EF09C000683D4 /* ILockable.cpp */,
|
||||
E8CF03D6178EF09C000683D4 /* ILockable.h */,
|
||||
E8CF03D8178EF165000683D4 /* AutoLocker.cpp */,
|
||||
E8CF03D9178EF166000683D4 /* AutoLocker.h */,
|
||||
E8CF03DE178EF4E9000683D4 /* IRunnable.cpp */,
|
||||
E8CF03DF178EF4E9000683D4 /* IRunnable.h */,
|
||||
E8CF0403178FF776000683D4 /* Exception.cpp */,
|
||||
|
@ -1878,6 +1871,8 @@
|
|||
E8E44682179CC4A400BE8855 /* Media */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E8403CB02299073400093C3E /* VoxelModelLoader.cpp */,
|
||||
E8403CAF2299073400093C3E /* VoxelModelLoader.h */,
|
||||
E8E44683179CC4DE00BE8855 /* Bitmap Codecs */,
|
||||
E88318D3179172AF002ABE6D /* Bitmap.cpp */,
|
||||
E88318D4179172AF002ABE6D /* Bitmap.h */,
|
||||
|
@ -2089,6 +2084,7 @@
|
|||
E82E675A18EA7972004DBA18 /* ALFuncs.cpp in Sources */,
|
||||
E82E675B18EA7972004DBA18 /* YsrDevice.cpp in Sources */,
|
||||
E82E675C18EA7972004DBA18 /* NullDevice.cpp in Sources */,
|
||||
E8403CB12299073400093C3E /* VoxelModelLoader.cpp in Sources */,
|
||||
E82E675D18EA7972004DBA18 /* PngWriter.cpp in Sources */,
|
||||
E82E675E18EA7972004DBA18 /* jpge.cpp in Sources */,
|
||||
E82E675F18EA7972004DBA18 /* IBitmapCodec.cpp in Sources */,
|
||||
|
@ -2115,9 +2111,7 @@
|
|||
E82E677418EA7972004DBA18 /* VersionInfo.cpp in Sources */,
|
||||
E82E677518EA7972004DBA18 /* Thread.cpp in Sources */,
|
||||
E82E677618EA7972004DBA18 /* Semaphore.cpp in Sources */,
|
||||
E82E677718EA7972004DBA18 /* Mutex.cpp in Sources */,
|
||||
E82E677818EA7972004DBA18 /* ILockable.cpp in Sources */,
|
||||
E82E677918EA7972004DBA18 /* AutoLocker.cpp in Sources */,
|
||||
E82E677A18EA7972004DBA18 /* IRunnable.cpp in Sources */,
|
||||
E82E677B18EA7972004DBA18 /* Exception.cpp in Sources */,
|
||||
E82E677C18EA7972004DBA18 /* DynamicLibrary.cpp in Sources */,
|
||||
|
|
|
@ -186,6 +186,8 @@ namespace spades {
|
|||
Matrix4 matrix;
|
||||
Vector3 customColor;
|
||||
bool depthHack;
|
||||
bool castShadow;
|
||||
bool unlit;
|
||||
}
|
||||
|
||||
class DynamicLightParam {
|
||||
|
|
|
@ -29,6 +29,7 @@ uniform sampler2D ambientOcclusionTexture;
|
|||
uniform sampler2D modelTexture;
|
||||
uniform vec3 fogColor;
|
||||
uniform vec3 customColor;
|
||||
uniform float modelOpacity;
|
||||
|
||||
vec3 EvaluateSunLight();
|
||||
vec3 EvaluateAmbientLight(float detailAmbientOcclusion);
|
||||
|
@ -54,6 +55,9 @@ void main() {
|
|||
(15. / 256.);
|
||||
ambientOcclusionCoord += .5 / 256.;
|
||||
|
||||
// Emissive material flag is encoded in AOID
|
||||
bool isEmissive = texData.w == 1.0;
|
||||
|
||||
// linearize
|
||||
gl_FragColor.xyz *= gl_FragColor.xyz;
|
||||
|
||||
|
@ -65,12 +69,17 @@ void main() {
|
|||
vec3 ao = texture2D(ambientOcclusionTexture, ambientOcclusionCoord).xyz;
|
||||
shading += EvaluateAmbientLight(ao.x);
|
||||
|
||||
gl_FragColor.xyz *= shading;
|
||||
if (!isEmissive) {
|
||||
gl_FragColor.xyz *= shading;
|
||||
}
|
||||
|
||||
gl_FragColor.xyz = mix(gl_FragColor.xyz, fogColor, fogDensity);
|
||||
|
||||
#if !LINEAR_FRAMEBUFFER
|
||||
gl_FragColor.xyz = sqrt(gl_FragColor.xyz);
|
||||
#endif
|
||||
|
||||
// Only valid in the ghost pass - Blending is disabled for most models
|
||||
gl_FragColor.w = modelOpacity;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,12 @@ void main() {
|
|||
if(dot(gl_FragColor.xyz, vec3(1.)) < 0.0001){
|
||||
gl_FragColor.xyz = customColor;
|
||||
}
|
||||
|
||||
|
||||
bool isEmissive = texData.w == 1.0;
|
||||
if (isEmissive) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// linearize
|
||||
gl_FragColor.xyz *= gl_FragColor.xyz;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
|
||||
varying vec4 color;
|
||||
varying vec3 emissionColor;
|
||||
varying vec2 ambientOcclusionCoord;
|
||||
//varying vec2 detailCoord;
|
||||
varying vec3 fogDensity;
|
||||
|
@ -28,6 +29,7 @@ varying vec3 fogDensity;
|
|||
uniform sampler2D ambientOcclusionTexture;
|
||||
uniform sampler2D detailTexture;
|
||||
uniform vec3 fogColor;
|
||||
uniform float modelOpacity;
|
||||
|
||||
vec3 EvaluateSunLight();
|
||||
vec3 EvaluateAmbientLight(float detailAmbientOcclusion);
|
||||
|
@ -35,8 +37,7 @@ vec3 EvaluateAmbientLight(float detailAmbientOcclusion);
|
|||
void main() {
|
||||
// color is linearized
|
||||
gl_FragColor = color;
|
||||
gl_FragColor.w = 1.;
|
||||
|
||||
|
||||
vec3 shading = vec3(color.w);
|
||||
|
||||
// FIXME: prepare for shadow?
|
||||
|
@ -46,7 +47,9 @@ void main() {
|
|||
shading += EvaluateAmbientLight(ao.x);
|
||||
|
||||
gl_FragColor.xyz *= shading;
|
||||
|
||||
|
||||
gl_FragColor.xyz += emissionColor;
|
||||
|
||||
//gl_FragColor.xyz *= texture2D(detailTexture, detailCoord).xyz * 2.;
|
||||
|
||||
gl_FragColor.xyz = mix(gl_FragColor.xyz, fogColor, fogDensity);
|
||||
|
@ -54,5 +57,8 @@ void main() {
|
|||
#if !LINEAR_FRAMEBUFFER
|
||||
gl_FragColor.xyz = sqrt(gl_FragColor.xyz);
|
||||
#endif
|
||||
|
||||
// Only valid in the ghost pass - Blending is disabled for most models
|
||||
gl_FragColor.w = modelOpacity;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ attribute vec3 normalAttribute;
|
|||
|
||||
varying vec2 ambientOcclusionCoord;
|
||||
varying vec4 color;
|
||||
varying vec3 emissionColor;
|
||||
varying vec3 fogDensity;
|
||||
//varying vec2 detailCoord;
|
||||
|
||||
|
@ -67,6 +68,17 @@ void main() {
|
|||
// linearize
|
||||
color.xyz *= color.xyz;
|
||||
|
||||
// material type (see `VoxelModel.h` for the definition)
|
||||
float materialType = colorAttribute.w * 255.0;
|
||||
|
||||
if (materialType > 0.5) {
|
||||
// emissive material
|
||||
emissionColor = color.xyz;
|
||||
color.xyz = vec3(0.0);
|
||||
} else {
|
||||
emissionColor = vec3(0.0);
|
||||
}
|
||||
|
||||
// direct sunlight
|
||||
vec3 normal = normalAttribute;
|
||||
normal = (modelNormalMatrix * vec4(normal, 1.)).xyz;
|
||||
|
|
|
@ -63,6 +63,14 @@ void main() {
|
|||
// linearize
|
||||
color.xyz *= color.xyz;
|
||||
|
||||
// material type (see `VoxelModel.h` for the definition)
|
||||
float materialType = colorAttribute.w * 255.0;
|
||||
|
||||
if (materialType > 0.5) {
|
||||
// emissive material - unaffected by dynamic lights
|
||||
color.xyz = vec3(0.0);
|
||||
}
|
||||
|
||||
// calculate normal
|
||||
vec3 normal = normalAttribute;
|
||||
normal = (modelNormalMatrix * vec4(normal, 1.)).xyz;
|
||||
|
|
|
@ -60,7 +60,7 @@ Make-Pak -PakName pak002-Base.pak -RelativePaths `
|
|||
Sounds/Misc, Sounds/Player, Textures
|
||||
|
||||
Make-Pak -PakName pak005-Models.pak -RelativePaths `
|
||||
Maps
|
||||
Maps, Models/MapObjects, Models/Player
|
||||
|
||||
Make-Pak -PakName pak010-BaseSkin.pak -RelativePaths `
|
||||
License/Credits-pak010-BaseSkin.md,
|
||||
|
|
|
@ -24,7 +24,7 @@ License/Credits-pak002-Base.md Gfx Scripts/Main.as \
|
|||
Scripts/Gui Scripts/Base Shaders \
|
||||
Sounds/Feedback Sounds/Misc Sounds/Player Textures $ZIPARGS > "$LOG_FILE"
|
||||
|
||||
zip -r "$OUTPUT_DIR/pak005-Models.pak" Maps $ZIPARGS > "$LOG_FILE"
|
||||
zip -r "$OUTPUT_DIR/pak005-Models.pak" Maps Models/MapObjects Models/Player $ZIPARGS > "$LOG_FILE"
|
||||
|
||||
zip -r "$OUTPUT_DIR/pak010-BaseSkin.pak" \
|
||||
License/Credits-pak010-BaseSkin.md \
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "CTFGameMode.h"
|
||||
|
@ -106,15 +108,31 @@ namespace spades {
|
|||
}
|
||||
}
|
||||
|
||||
void RenderModel(IModel *model, const ModelRenderParam &p) {
|
||||
void RenderModel(IModel *model, const ModelRenderParam &_p) {
|
||||
ModelRenderParam p = _p;
|
||||
|
||||
if (!model) {
|
||||
SPInvalidArgument("model");
|
||||
return;
|
||||
}
|
||||
|
||||
if (p.depthHack && !allowDepthHack) {
|
||||
OnProhibitedAction();
|
||||
return;
|
||||
}
|
||||
|
||||
// Overbright surfaces bypass the fog
|
||||
p.customColor.x = std::max(std::min(p.customColor.x, 1.0f), 0.0f);
|
||||
p.customColor.y = std::max(std::min(p.customColor.y, 1.0f), 0.0f);
|
||||
p.customColor.z = std::max(std::min(p.customColor.z, 1.0f), 0.0f);
|
||||
|
||||
// NaN values bypass the fog
|
||||
if (std::isnan(p.customColor.x) || std::isnan(p.customColor.y) ||
|
||||
std::isnan(p.customColor.z)) {
|
||||
OnProhibitedAction();
|
||||
return;
|
||||
}
|
||||
|
||||
auto bounds = (p.matrix * OBB3(model->GetBoundingBox())).GetBoundingAABB();
|
||||
if (CheckVisibility(bounds)) {
|
||||
base->RenderModel(model, p);
|
||||
|
|
|
@ -68,6 +68,10 @@ namespace spades {
|
|||
for (size_t i = 0; i < blocks.size(); i++) {
|
||||
IntVector3 v = blocks[i];
|
||||
uint32_t col = map->GetColor(v.x, v.y, v.z);
|
||||
|
||||
// Use the default material
|
||||
col &= 0xffffff;
|
||||
|
||||
vmodel->SetSolid(v.x - minX, v.y - minY, v.z - minZ, col);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <vector>
|
||||
|
||||
#include "GameMap.h"
|
||||
#include <Core/AutoLocker.h>
|
||||
#include <Core/Debug.h>
|
||||
#include <Core/Exception.h>
|
||||
#include <Core/FileManager.h>
|
||||
|
@ -51,12 +50,12 @@ namespace spades {
|
|||
GameMap::~GameMap() { SPADES_MARK_FUNCTION(); }
|
||||
|
||||
void GameMap::AddListener(spades::client::IGameMapListener *l) {
|
||||
AutoLocker guard(&listenersMutex);
|
||||
std::lock_guard<std::mutex> _guard{listenersMutex};
|
||||
listeners.push_back(l);
|
||||
}
|
||||
|
||||
void GameMap::RemoveListener(spades::client::IGameMapListener *l) {
|
||||
AutoLocker guard(&listenersMutex);
|
||||
std::lock_guard<std::mutex> _guard{listenersMutex};
|
||||
auto it = std::find(listeners.begin(), listeners.end(), l);
|
||||
if (it != listeners.end()) {
|
||||
listeners.erase(it);
|
||||
|
|
|
@ -24,13 +24,12 @@
|
|||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
#include <Core/Debug.h>
|
||||
#include <Core/Math.h>
|
||||
|
||||
#include "IGameMapListener.h"
|
||||
#include <Core/AutoLocker.h>
|
||||
#include <Core/Mutex.h>
|
||||
#include <Core/RefCountedObject.h>
|
||||
|
||||
namespace spades {
|
||||
|
@ -127,11 +126,9 @@ namespace spades {
|
|||
}
|
||||
if (!unsafe) {
|
||||
if (changed) {
|
||||
{
|
||||
AutoLocker guard(&listenersMutex);
|
||||
for (auto *l : listeners) {
|
||||
l->GameMapChanged(x, y, z, this);
|
||||
}
|
||||
std::lock_guard<std::mutex> guard{listenersMutex};
|
||||
for (auto *l : listeners) {
|
||||
l->GameMapChanged(x, y, z, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,9 +160,9 @@ namespace spades {
|
|||
uint64_t solidMap[DefaultWidth][DefaultHeight];
|
||||
uint32_t colorMap[DefaultWidth][DefaultHeight][DefaultDepth];
|
||||
std::list<IGameMapListener *> listeners;
|
||||
Mutex listenersMutex;
|
||||
std::mutex listenersMutex;
|
||||
|
||||
bool IsSurface(int x, int y, int z);
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace client
|
||||
} // namespace spades
|
||||
|
|
|
@ -37,37 +37,52 @@ namespace spades {
|
|||
class GameMap;
|
||||
|
||||
struct ModelRenderParam {
|
||||
Matrix4 matrix;
|
||||
Vector3 customColor;
|
||||
bool depthHack;
|
||||
|
||||
ModelRenderParam() {
|
||||
matrix = Matrix4::Identity();
|
||||
customColor = MakeVector3(0, 0, 0);
|
||||
depthHack = false;
|
||||
}
|
||||
/** The transformatrix matrix applied on the model. */
|
||||
Matrix4 matrix = Matrix4::Identity();
|
||||
/** Voxels having a color value `(0, 0, 0)` are replaced with
|
||||
* this color. */
|
||||
Vector3 customColor = MakeVector3(0, 0, 0);
|
||||
/** Specifies to render the model in front of other non-depth-hack
|
||||
* models. Useful for first-person models. */
|
||||
bool depthHack = false;
|
||||
/** Specifies whether the model casts a shadow. */
|
||||
bool castShadow = true;
|
||||
/**
|
||||
* Specifies that the model is not an actual object in the virtual world, thus does not
|
||||
* affect the shading of other objects and does not appear in a mirror.
|
||||
*
|
||||
* This excludes the model from visual effects such as shadowing, global illumination
|
||||
* (specifically, screen-space ambient occlusion, ATM), and dynamic lighting.
|
||||
* In exchange, it allows the use of an opacity value other than `1`.
|
||||
*
|
||||
* `ghost` implies `!castShadow`.
|
||||
*/
|
||||
bool ghost = false;
|
||||
/** Specifies the opacity of the model. Ignored if `ghost` is `false`. */
|
||||
float opacity = 1.0;
|
||||
};
|
||||
|
||||
enum DynamicLightType { DynamicLightTypePoint, DynamicLightTypeSpotlight };
|
||||
|
||||
struct DynamicLightParam {
|
||||
DynamicLightType type;
|
||||
DynamicLightType type = DynamicLightTypePoint;
|
||||
/** The position of the light. */
|
||||
Vector3 origin;
|
||||
/** The effective radius of the light. Objects outside this radius
|
||||
* is unaffected by the light. */
|
||||
float radius;
|
||||
Vector3 color;
|
||||
|
||||
/** The basis vectors specifying the orientation of a spotlight.
|
||||
* See the existing code for usage. */
|
||||
std::array<Vector3, 3> spotAxis;
|
||||
IImage *image;
|
||||
float spotAngle;
|
||||
/** The projected image for a spotlight. */
|
||||
IImage *image = nullptr;
|
||||
float spotAngle = 0.0f;
|
||||
|
||||
bool useLensFlare;
|
||||
|
||||
DynamicLightParam() {
|
||||
image = NULL;
|
||||
type = DynamicLightTypePoint;
|
||||
spotAngle = 0.f;
|
||||
useLensFlare = false;
|
||||
}
|
||||
/** When set to `true`, the lens flare post-effect is enabled for
|
||||
* the light. */
|
||||
bool useLensFlare = false;
|
||||
};
|
||||
|
||||
class IRenderer : public RefCountedObject {
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013 yvt
|
||||
|
||||
This file is part of OpenSpades.
|
||||
|
||||
OpenSpades is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenSpades is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "AutoLocker.h"
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013 yvt
|
||||
|
||||
This file is part of OpenSpades.
|
||||
|
||||
OpenSpades is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenSpades is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ILockable.h"
|
||||
|
||||
namespace spades {
|
||||
class AutoLocker {
|
||||
ILockable *lockable;
|
||||
|
||||
public:
|
||||
AutoLocker(ILockable *l) : lockable(l) {
|
||||
if (lockable)
|
||||
lockable->Lock();
|
||||
}
|
||||
AutoLocker(const AutoLocker &l) : lockable(l.lockable) {
|
||||
if (lockable)
|
||||
lockable->Lock();
|
||||
}
|
||||
~AutoLocker() {
|
||||
if (lockable)
|
||||
lockable->Unlock();
|
||||
}
|
||||
ILockable *Release() {
|
||||
ILockable *l = lockable;
|
||||
lockable = 0;
|
||||
return l;
|
||||
}
|
||||
ILockable *GetLockable() { return lockable; }
|
||||
void operator=(const AutoLocker &l) {
|
||||
if (l.lockable)
|
||||
l.lockable->Lock();
|
||||
if (lockable)
|
||||
lockable->Unlock();
|
||||
lockable = l.lockable;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -39,11 +39,9 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "AutoLocker.h"
|
||||
#include "ConcurrentDispatch.h"
|
||||
#include "Debug.h"
|
||||
#include "Exception.h"
|
||||
#include "Mutex.h"
|
||||
#include "Settings.h"
|
||||
#include "Thread.h"
|
||||
#include <OpenSpades.h>
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013 yvt
|
||||
|
||||
This file is part of OpenSpades.
|
||||
|
||||
OpenSpades is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenSpades is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "Mutex.h"
|
||||
#include <Imports/SDL.h>
|
||||
|
||||
namespace spades {
|
||||
Mutex::Mutex() { priv = (void *)SDL_CreateMutex(); }
|
||||
|
||||
Mutex::~Mutex() { SDL_DestroyMutex((SDL_mutex *)priv); }
|
||||
|
||||
void Mutex::Lock() { SDL_mutexP((SDL_mutex *)priv); }
|
||||
|
||||
void Mutex::Unlock() { SDL_mutexV((SDL_mutex *)priv); }
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013 yvt
|
||||
|
||||
This file is part of OpenSpades.
|
||||
|
||||
OpenSpades is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenSpades is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "ILockable.h"
|
||||
|
||||
namespace spades {
|
||||
/** Recursive mutex. */
|
||||
class Mutex : public ILockable {
|
||||
void *priv;
|
||||
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
void Lock() override;
|
||||
void Unlock() override;
|
||||
};
|
||||
}
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "RefCountedObject.h"
|
||||
#include <ScriptBindings/ScriptManager.h>
|
||||
#include "AutoLocker.h"
|
||||
#include "Exception.h"
|
||||
|
||||
namespace spades {
|
||||
|
@ -32,7 +31,7 @@ namespace spades {
|
|||
|
||||
void RefCountedObject::Release() {
|
||||
#if DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE
|
||||
AutoLocker guard(&releaseInfoMutex);
|
||||
std::lock_guard<std::mutex> guard{releaseInfoMutex};
|
||||
#endif
|
||||
int cnt = refCount.fetch_sub(1);
|
||||
if (cnt == 1) {
|
||||
|
|
|
@ -25,10 +25,13 @@
|
|||
#include <typeinfo>
|
||||
|
||||
#include "Debug.h"
|
||||
#include "Mutex.h"
|
||||
|
||||
#define DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE 0
|
||||
|
||||
#if DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
namespace spades {
|
||||
|
||||
class RefCountedObject {
|
||||
|
@ -36,7 +39,7 @@ namespace spades {
|
|||
#if DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE
|
||||
reflection::BacktraceRecord lastRelease;
|
||||
reflection::BacktraceRecord secondLastRelease;
|
||||
Mutex releaseInfoMutex;
|
||||
std::mutex releaseInfoMutex;
|
||||
#endif
|
||||
protected:
|
||||
virtual ~RefCountedObject();
|
||||
|
@ -147,11 +150,9 @@ namespace spades {
|
|||
}
|
||||
|
||||
/**
|
||||
* Attempts to cast this `Handle<T>` to `Handle<S>` using `dynamic_cast`.
|
||||
* Throws an exception if the cast was unsuccessful.
|
||||
*/
|
||||
template <class S> Handle<S> Cast() const & {
|
||||
return Handle{*this}.Cast<S>();
|
||||
}
|
||||
* Attempts to cast this `Handle<T>` to `Handle<S>` using `dynamic_cast`.
|
||||
* Throws an exception if the cast was unsuccessful.
|
||||
*/
|
||||
template <class S> Handle<S> Cast() const & { return Handle{*this}.Cast<S>(); }
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
|
||||
*/
|
||||
|
||||
#include <mutex>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <Imports/SDL.h>
|
||||
|
||||
#include "AutoLocker.h"
|
||||
#include "ConcurrentDispatch.h"
|
||||
#include "Debug.h"
|
||||
#include "Thread.h"
|
||||
|
@ -39,15 +39,15 @@ namespace spades {
|
|||
|
||||
class ThreadCleanuper : public ConcurrentDispatch {
|
||||
std::vector<SDL_Thread *> threads;
|
||||
Mutex mutex;
|
||||
std::recursive_mutex mutex;
|
||||
|
||||
public:
|
||||
void Add(SDL_Thread *thread) {
|
||||
AutoLocker locker(&mutex);
|
||||
std::lock_guard<std::recursive_mutex> _lock{this->mutex};
|
||||
threads.push_back(thread);
|
||||
}
|
||||
void Cleanup() {
|
||||
AutoLocker locker(&mutex);
|
||||
std::lock_guard<std::recursive_mutex> _lock{this->mutex};
|
||||
for (size_t i = 0; i < threads.size(); i++)
|
||||
SDL_WaitThread(threads[i], NULL);
|
||||
threads.clear();
|
||||
|
@ -63,7 +63,7 @@ namespace spades {
|
|||
Thread::~Thread() {
|
||||
SDL_Thread *th = NULL;
|
||||
{
|
||||
AutoLocker locker(&lock);
|
||||
std::lock_guard<std::recursive_mutex> _lock{this->lock};
|
||||
th = (SDL_Thread *)threadInfo;
|
||||
if (!th)
|
||||
return;
|
||||
|
@ -80,7 +80,7 @@ namespace spades {
|
|||
}
|
||||
|
||||
void Thread::Start() {
|
||||
AutoLocker locker(&lock);
|
||||
std::lock_guard<std::recursive_mutex> _lock{this->lock};
|
||||
if (threadInfo)
|
||||
return;
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace spades {
|
|||
}
|
||||
SDL_Thread *th = NULL;
|
||||
{
|
||||
AutoLocker locker(&lock);
|
||||
std::lock_guard<std::recursive_mutex> _lock{this->lock};
|
||||
th = (SDL_Thread *)threadInfo;
|
||||
if (!th)
|
||||
return;
|
||||
|
@ -137,13 +137,13 @@ namespace spades {
|
|||
}
|
||||
|
||||
void Thread::Quited() {
|
||||
lock.Lock();
|
||||
lock.lock();
|
||||
threadInfo = NULL;
|
||||
if (autoDelete) {
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
lock.Unlock();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
void Thread::Run() {
|
||||
|
@ -152,13 +152,14 @@ namespace spades {
|
|||
}
|
||||
|
||||
void Thread::MarkForAutoDeletion() {
|
||||
lock.Lock();
|
||||
lock.lock();
|
||||
if (threadInfo == NULL) {
|
||||
// already exited
|
||||
lock.unlock();
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
autoDelete = true;
|
||||
lock.Unlock();
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
} // namespace spades
|
||||
|
|
|
@ -21,15 +21,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <Imports/SDL.h>
|
||||
#include <mutex>
|
||||
|
||||
#include "IRunnable.h"
|
||||
#include "Mutex.h"
|
||||
|
||||
namespace spades {
|
||||
|
||||
class Thread {
|
||||
void *threadInfo;
|
||||
Mutex lock;
|
||||
std::recursive_mutex lock;
|
||||
IRunnable *runnable;
|
||||
bool autoDelete;
|
||||
SDL_threadID threadId;
|
||||
|
|
|
@ -54,6 +54,13 @@ namespace spades {
|
|||
delete[] colors;
|
||||
}
|
||||
|
||||
void VoxelModel::ForceMaterial(MaterialType newMaterialId) {
|
||||
int count = width * height * depth;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
colors[i] = (colors[i] & 0xffffff) | (static_cast<uint32_t>(newMaterialId) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
struct KV6Block {
|
||||
uint32_t color;
|
||||
uint16_t zPos;
|
||||
|
|
|
@ -22,12 +22,20 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#include <Core/Debug.h>
|
||||
#include "IStream.h"
|
||||
#include "Math.h"
|
||||
#include <Core/Debug.h>
|
||||
#include <Core/RefCountedObject.h>
|
||||
|
||||
namespace spades {
|
||||
/**
|
||||
* Material IDs used by `VoxelModel`.
|
||||
*/
|
||||
enum class MaterialType : uint8_t {
|
||||
Default = 0,
|
||||
Emissive = 1,
|
||||
};
|
||||
|
||||
class VoxelModel : public RefCountedObject {
|
||||
Vector3 origin;
|
||||
int width, height, depth;
|
||||
|
@ -42,8 +50,19 @@ namespace spades {
|
|||
|
||||
void HollowFill();
|
||||
|
||||
/**
|
||||
* Load a `VoxelModel` from a stream in the KV6 format.
|
||||
*
|
||||
* The KV6 format does not include material information, so the material
|
||||
* IDs of the loaded voxels are set to `0`.
|
||||
*/
|
||||
static VoxelModel *LoadKV6(IStream *);
|
||||
|
||||
/**
|
||||
* Replace the material ID with the specified value.
|
||||
*/
|
||||
void ForceMaterial(MaterialType newMaterialId);
|
||||
|
||||
const uint64_t &GetSolidBitsAt(int x, int y) const {
|
||||
SPAssert(x >= 0);
|
||||
SPAssert(x < width);
|
||||
|
@ -59,6 +78,13 @@ namespace spades {
|
|||
return solidBits[x + y * width];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the color value of a voxel.
|
||||
*
|
||||
* The color value is a 32-bit value where the lower 24 bits represent
|
||||
* a color. The remaining 8 bits represent a material ID. See
|
||||
* `MaterialType` for the predefined material IDs.
|
||||
*/
|
||||
const uint32_t &GetColor(int x, int y, int z) const {
|
||||
SPAssert(x >= 0);
|
||||
SPAssert(x < width);
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Copyright (c) 2019 yvt
|
||||
|
||||
This file is part of OpenSpades.
|
||||
|
||||
OpenSpades is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenSpades is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "VoxelModelLoader.h"
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <Core/Debug.h>
|
||||
#include <Core/Exception.h>
|
||||
#include <Core/FileManager.h>
|
||||
#include <Core/IStream.h>
|
||||
#include <Core/Math.h>
|
||||
#include <Core/TMPUtils.h>
|
||||
#include <Core/VoxelModel.h>
|
||||
|
||||
namespace spades {
|
||||
namespace {
|
||||
// Copied from `ngspades`, a cancelled branch of OpenSpades
|
||||
Vector3 ReadVector3(const Json::Value &json, const char *name) {
|
||||
if (json.isArray() && json.size() == 3) {
|
||||
auto e1 = json.get((Json::UInt)0, Json::nullValue);
|
||||
auto e2 = json.get((Json::UInt)1, Json::nullValue);
|
||||
auto e3 = json.get((Json::UInt)2, Json::nullValue);
|
||||
if (e1.isConvertibleTo(Json::ValueType::realValue) &&
|
||||
e2.isConvertibleTo(Json::ValueType::realValue) &&
|
||||
e3.isConvertibleTo(Json::ValueType::realValue)) {
|
||||
return Vector3(e1.asDouble(), e2.asDouble(), e3.asDouble());
|
||||
}
|
||||
}
|
||||
SPRaise("%s must be vector consisting of three real values", name);
|
||||
}
|
||||
|
||||
struct Metadata {
|
||||
stmp::optional<Vector3> origin;
|
||||
stmp::optional<MaterialType> forceMaterial;
|
||||
|
||||
void Parse(const Json::Value &root) {
|
||||
if (root.type() == Json::objectValue) {
|
||||
auto jsonOrigin = root.get("Origin", Json::nullValue);
|
||||
if (!jsonOrigin.isNull()) {
|
||||
origin = ReadVector3(jsonOrigin, "Origin");
|
||||
}
|
||||
|
||||
auto jsonForceMaterial = root.get("ForceMaterial", Json::nullValue);
|
||||
if (!jsonForceMaterial.isNull()) {
|
||||
if (!jsonForceMaterial.isString()) {
|
||||
SPRaise("ForceMaterial must be a string");
|
||||
}
|
||||
|
||||
auto str = jsonForceMaterial.asString();
|
||||
if (str == "Default") {
|
||||
forceMaterial = MaterialType::Default;
|
||||
} else if (str == "Emissive") {
|
||||
forceMaterial = MaterialType::Emissive;
|
||||
} else {
|
||||
SPRaise("ForceMaterial: Unrecognized value '%s'", str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
VoxelModel *VoxelModelLoader::Load(const char *path) {
|
||||
// Load the metadata file
|
||||
std::string metadataPath = path;
|
||||
{
|
||||
auto i = metadataPath.rfind('.');
|
||||
if (i != std::string::npos) {
|
||||
metadataPath.resize(i);
|
||||
}
|
||||
metadataPath += ".meta.json";
|
||||
}
|
||||
|
||||
// Load the metadata
|
||||
Metadata meta;
|
||||
if (FileManager::FileExists(metadataPath.c_str())) {
|
||||
SPLog("Found a metadata file '%s', loading it...", metadataPath.c_str());
|
||||
|
||||
std::string metadataJson = FileManager::ReadAllBytes(metadataPath.c_str());
|
||||
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
|
||||
if (reader.parse(metadataJson, root, false)) {
|
||||
meta.Parse(root);
|
||||
} else {
|
||||
SPRaise("The voxel model metadata file is not a valid JSON file.");
|
||||
}
|
||||
} else {
|
||||
SPLog("Ignoring a non-existend metadata file '%s'.", metadataPath.c_str());
|
||||
}
|
||||
|
||||
// Load the base KV6 model
|
||||
Handle<VoxelModel> voxelModel;
|
||||
{
|
||||
SPLog("Loading '%s' as a KV6 voxel model.", path);
|
||||
std::unique_ptr<IStream> stream{FileManager::OpenForReading(path)};
|
||||
voxelModel = Handle<VoxelModel>{VoxelModel::LoadKV6(stream.get()), false};
|
||||
}
|
||||
|
||||
// Apply transformation requested by the metadata
|
||||
if (meta.origin) {
|
||||
voxelModel->SetOrigin(*meta.origin);
|
||||
}
|
||||
|
||||
if (meta.forceMaterial) {
|
||||
voxelModel->ForceMaterial(*meta.forceMaterial);
|
||||
}
|
||||
|
||||
return voxelModel.Unmanage();
|
||||
}
|
||||
} // namespace spades
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright (c) 2019 yvt
|
||||
|
||||
This file is part of OpenSpades.
|
||||
|
||||
OpenSpades is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenSpades is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace spades {
|
||||
class VoxelModel;
|
||||
|
||||
/**
|
||||
* Provides a method for loading `VoxelModel` augmented by metadata.
|
||||
*/
|
||||
class VoxelModelLoader final {
|
||||
VoxelModelLoader() = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Load a `VoxelModel` from the specified `FileManager`-style path.
|
||||
*
|
||||
* In addition to loading the file at `path`, this method also loads
|
||||
* metadata from `BASENAME.meta.json` (where `BASENAME` is a portion of
|
||||
* `path` without a file extension).
|
||||
*
|
||||
* All supported fields of a metadata file are shown below:
|
||||
*
|
||||
* {
|
||||
* // Override the origin point
|
||||
* "Origin": [0.3, 0.5, 0.7],
|
||||
*
|
||||
* // Replace the material ID
|
||||
* "ForceMaterial": "Default",
|
||||
* "ForceMaterial": "Emissive",
|
||||
*
|
||||
* // (All fields are optional)
|
||||
* }
|
||||
*/
|
||||
static VoxelModel *Load(const char *path);
|
||||
};
|
||||
} // namespace spades
|
|
@ -40,10 +40,12 @@ namespace spades {
|
|||
virtual void RenderShadowMapPass(std::vector<client::ModelRenderParam> params) = 0;
|
||||
|
||||
/** Renders only in depth buffer (optional) */
|
||||
virtual void Prerender(std::vector<client::ModelRenderParam> params) = 0;
|
||||
virtual void Prerender(std::vector<client::ModelRenderParam> params,
|
||||
bool ghostPass) = 0;
|
||||
|
||||
/** Renders sunlighted solid geometry */
|
||||
virtual void RenderSunlightPass(std::vector<client::ModelRenderParam> params) = 0;
|
||||
virtual void RenderSunlightPass(std::vector<client::ModelRenderParam> params,
|
||||
bool ghostPass) = 0;
|
||||
|
||||
/** Adds dynamic light */
|
||||
virtual void RenderDynamicLightPass(std::vector<client::ModelRenderParam> params,
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
#include <memory>
|
||||
|
||||
#include "GLModelManager.h"
|
||||
#include "GLRenderer.h"
|
||||
#include "GLVoxelModel.h"
|
||||
#include <Core/Debug.h>
|
||||
#include <Core/FileManager.h>
|
||||
#include <Core/IStream.h>
|
||||
#include <Core/Settings.h>
|
||||
#include <Core/VoxelModel.h>
|
||||
#include "GLRenderer.h"
|
||||
#include "GLVoxelModel.h"
|
||||
#include <Core/VoxelModelLoader.h>
|
||||
|
||||
namespace spades {
|
||||
namespace draw {
|
||||
|
@ -62,10 +62,9 @@ namespace spades {
|
|||
GLModel *GLModelManager::CreateModel(const char *name) {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
std::unique_ptr<IStream> stream{FileManager::OpenForReading(name)};
|
||||
Handle<VoxelModel> voxelModel{VoxelModel::LoadKV6(stream.get()), false};
|
||||
Handle<VoxelModel> voxelModel{VoxelModelLoader::Load(name), false};
|
||||
|
||||
return static_cast<GLModel *>(renderer->CreateModelOptimized(voxelModel));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace draw
|
||||
} // namespace spades
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace spades {
|
|||
#endif
|
||||
}
|
||||
|
||||
void GLModelRenderer::Prerender() {
|
||||
void GLModelRenderer::Prerender(bool ghostPass) {
|
||||
device->ColorMask(false, false, false, false);
|
||||
|
||||
GLProfiler::Context profiler(renderer->GetGLProfiler(), "Model [%d model(s), %d unique model type(s)]", modelCount,
|
||||
|
@ -78,13 +78,13 @@ namespace spades {
|
|||
for (size_t i = 0; i < models.size(); i++) {
|
||||
RenderModel &m = models[i];
|
||||
GLModel *model = m.model;
|
||||
model->Prerender(m.params);
|
||||
model->Prerender(m.params, ghostPass);
|
||||
numModels += (int)m.params.size();
|
||||
}
|
||||
device->ColorMask(true, true, true, true);
|
||||
}
|
||||
|
||||
void GLModelRenderer::RenderSunlightPass() {
|
||||
void GLModelRenderer::RenderSunlightPass(bool ghostPass) {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
GLProfiler::Context profiler(renderer->GetGLProfiler(), "Model [%d model(s), %d unique model type(s)]", modelCount,
|
||||
|
@ -94,7 +94,7 @@ namespace spades {
|
|||
RenderModel &m = models[i];
|
||||
GLModel *model = m.model;
|
||||
|
||||
model->RenderSunlightPass(m.params);
|
||||
model->RenderSunlightPass(m.params, ghostPass);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,8 +54,8 @@ namespace spades {
|
|||
|
||||
void RenderShadowMapPass();
|
||||
|
||||
void Prerender();
|
||||
void RenderSunlightPass();
|
||||
void Prerender(bool ghostPass);
|
||||
void RenderSunlightPass(bool ghostPass);
|
||||
void RenderDynamicLightPass(std::vector<GLDynamicLight> lights);
|
||||
|
||||
void Clear();
|
||||
|
|
|
@ -343,14 +343,27 @@ namespace spades {
|
|||
|
||||
SPAssert(model->IsSolid(p3.x, p3.y, p3.z));
|
||||
uint32_t col = model->GetColor(p3.x, p3.y, p3.z);
|
||||
auto material = static_cast<MaterialType>(col >> 24);
|
||||
|
||||
col &= 0xffffff;
|
||||
|
||||
// add AOID
|
||||
p3 += nn;
|
||||
SPAssert(!model->IsSolid(p3.x, p3.y, p3.z));
|
||||
uint8_t aoId = calcAOID(model, p3.x, p3.y, p3.z, ux, uy, uz, vx, vy, vz);
|
||||
col |= ((uint8_t)aoId) << 24;
|
||||
// Add AOID (selector for the pre-integrated ambient occlusion texture).
|
||||
// Use special values for certain materials.
|
||||
if (material == MaterialType::Emissive) {
|
||||
col |= ((uint32_t)255) << 24;
|
||||
} else {
|
||||
p3 += nn;
|
||||
SPAssert(!model->IsSolid(p3.x, p3.y, p3.z));
|
||||
|
||||
uint8_t aoId = calcAOID(model, p3.x, p3.y, p3.z, ux, uy, uz, vx, vy, vz);
|
||||
|
||||
if (aoId % 16 == 15) {
|
||||
// These AOIDs are allocated for non-default materials.
|
||||
aoId = 15;
|
||||
}
|
||||
|
||||
col |= ((uint8_t)aoId) << 24;
|
||||
}
|
||||
|
||||
*(pixels++) = col;
|
||||
|
||||
|
@ -511,10 +524,11 @@ namespace spades {
|
|||
printf("%d vertices emit\n", (int)indices.size());
|
||||
}
|
||||
|
||||
void GLOptimizedVoxelModel::Prerender(std::vector<client::ModelRenderParam> params) {
|
||||
void GLOptimizedVoxelModel::Prerender(std::vector<client::ModelRenderParam> params,
|
||||
bool ghostPass) {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
RenderSunlightPass(params);
|
||||
RenderSunlightPass(params, ghostPass);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -558,6 +572,10 @@ namespace spades {
|
|||
for (size_t i = 0; i < params.size(); i++) {
|
||||
const client::ModelRenderParam ¶m = params[i];
|
||||
|
||||
if (!param.castShadow || param.ghost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// frustrum cull
|
||||
float rad = radius;
|
||||
rad *= param.matrix.GetAxis(0).GetLength();
|
||||
|
@ -596,8 +614,8 @@ namespace spades {
|
|||
device->BindTexture(IGLDevice::Texture2D, 0);
|
||||
}
|
||||
|
||||
void
|
||||
GLOptimizedVoxelModel::RenderSunlightPass(std::vector<client::ModelRenderParam> params) {
|
||||
void GLOptimizedVoxelModel::RenderSunlightPass(std::vector<client::ModelRenderParam> params,
|
||||
bool ghostPass) {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
bool mirror = renderer->IsRenderingMirror();
|
||||
|
@ -689,6 +707,10 @@ namespace spades {
|
|||
if (mirror && param.depthHack)
|
||||
continue;
|
||||
|
||||
if (param.ghost != ghostPass) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// frustrum cull
|
||||
float rad = radius;
|
||||
rad *= param.matrix.GetAxis(0).GetLength();
|
||||
|
@ -721,6 +743,10 @@ namespace spades {
|
|||
modelNormalMatrix(program);
|
||||
modelNormalMatrix.SetValue(modelMatrix);
|
||||
|
||||
static GLProgramUniform modelOpacity("modelOpacity");
|
||||
modelOpacity(program);
|
||||
modelOpacity.SetValue(param.opacity);
|
||||
|
||||
if (param.depthHack) {
|
||||
device->DepthRange(0.f, 0.1f);
|
||||
}
|
||||
|
@ -821,6 +847,9 @@ namespace spades {
|
|||
if (mirror && param.depthHack)
|
||||
continue;
|
||||
|
||||
if (param.ghost)
|
||||
continue;
|
||||
|
||||
// frustrum cull
|
||||
float rad = radius;
|
||||
rad *= param.matrix.GetAxis(0).GetLength();
|
||||
|
|
|
@ -86,11 +86,12 @@ namespace spades {
|
|||
|
||||
static void PreloadShaders(GLRenderer *);
|
||||
|
||||
void Prerender(std::vector<client::ModelRenderParam> params) override;
|
||||
void Prerender(std::vector<client::ModelRenderParam> params, bool ghostPass) override;
|
||||
|
||||
void RenderShadowMapPass(std::vector<client::ModelRenderParam> params) override;
|
||||
|
||||
void RenderSunlightPass(std::vector<client::ModelRenderParam> params) override;
|
||||
void RenderSunlightPass(std::vector<client::ModelRenderParam> params,
|
||||
bool ghostPass) override;
|
||||
|
||||
void RenderDynamicLightPass(std::vector<client::ModelRenderParam> params,
|
||||
std::vector<GLDynamicLight> lights) override;
|
||||
|
|
|
@ -620,7 +620,7 @@ namespace spades {
|
|||
mapRenderer->Prerender();
|
||||
}
|
||||
if (needsFullDepthPrepass) {
|
||||
modelRenderer->Prerender();
|
||||
modelRenderer->Prerender(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,7 +650,7 @@ namespace spades {
|
|||
if (!sceneDef.skipWorld && mapRenderer) {
|
||||
mapRenderer->RenderSunlightPass();
|
||||
}
|
||||
modelRenderer->RenderSunlightPass();
|
||||
modelRenderer->RenderSunlightPass(false);
|
||||
}
|
||||
if (settings.r_ssao) {
|
||||
device->BindTexture(IGLDevice::Texture2D, ssaoBufferTexture);
|
||||
|
@ -683,6 +683,32 @@ namespace spades {
|
|||
}
|
||||
}
|
||||
|
||||
void GLRenderer::RenderGhosts() {
|
||||
// Run a depth-only pass so that for each pixel, objects are drawn
|
||||
// only once
|
||||
{
|
||||
GLProfiler::Context p(*profiler, "Depth-only Prepass");
|
||||
device->DepthFunc(IGLDevice::Less);
|
||||
modelRenderer->Prerender(true);
|
||||
}
|
||||
|
||||
// Run a color pass
|
||||
{
|
||||
GLProfiler::Context p(*profiler, "Ghost Pass");
|
||||
|
||||
device->Enable(IGLDevice::Blend, true);
|
||||
device->DepthMask(false);
|
||||
device->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha, IGLDevice::Zero,
|
||||
IGLDevice::One);
|
||||
device->DepthFunc(IGLDevice::Equal);
|
||||
modelRenderer->RenderSunlightPass(true);
|
||||
}
|
||||
device->DepthMask(true);
|
||||
device->DepthFunc(IGLDevice::Less);
|
||||
device->Enable(IGLDevice::Blend, false);
|
||||
device->Enable(IGLDevice::CullFace, false);
|
||||
}
|
||||
|
||||
void GLRenderer::EndScene() {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
|
@ -831,6 +857,11 @@ namespace spades {
|
|||
waterRenderer->Render();
|
||||
}
|
||||
|
||||
{
|
||||
GLProfiler::Context p(*profiler, "Ghosts");
|
||||
RenderGhosts();
|
||||
}
|
||||
|
||||
device->Enable(IGLDevice::Blend, true);
|
||||
|
||||
device->DepthMask(false);
|
||||
|
|
|
@ -135,6 +135,7 @@ namespace spades {
|
|||
void RenderDebugLines();
|
||||
|
||||
void RenderObjects();
|
||||
void RenderGhosts();
|
||||
|
||||
void EnsureInitialized();
|
||||
void EnsureSceneStarted();
|
||||
|
|
|
@ -257,10 +257,10 @@ namespace spades {
|
|||
}
|
||||
}
|
||||
|
||||
void GLVoxelModel::Prerender(std::vector<client::ModelRenderParam> params) {
|
||||
void GLVoxelModel::Prerender(std::vector<client::ModelRenderParam> params, bool ghostPass) {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
RenderSunlightPass(params);
|
||||
RenderSunlightPass(params, ghostPass);
|
||||
}
|
||||
|
||||
void GLVoxelModel::RenderShadowMapPass(std::vector<client::ModelRenderParam> params) {
|
||||
|
@ -303,6 +303,10 @@ namespace spades {
|
|||
for (size_t i = 0; i < params.size(); i++) {
|
||||
const client::ModelRenderParam ¶m = params[i];
|
||||
|
||||
if (!param.castShadow || param.ghost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// frustrum cull
|
||||
float rad = radius;
|
||||
rad *= param.matrix.GetAxis(0).GetLength();
|
||||
|
@ -341,7 +345,7 @@ namespace spades {
|
|||
device->BindTexture(IGLDevice::Texture2D, 0);
|
||||
}
|
||||
|
||||
void GLVoxelModel::RenderSunlightPass(std::vector<client::ModelRenderParam> params) {
|
||||
void GLVoxelModel::RenderSunlightPass(std::vector<client::ModelRenderParam> params, bool ghostPass) {
|
||||
SPADES_MARK_FUNCTION();
|
||||
|
||||
device->ActiveTexture(0);
|
||||
|
@ -418,6 +422,10 @@ namespace spades {
|
|||
for (size_t i = 0; i < params.size(); i++) {
|
||||
const client::ModelRenderParam ¶m = params[i];
|
||||
|
||||
if (param.ghost != ghostPass) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// frustrum cull
|
||||
float rad = radius;
|
||||
rad *= param.matrix.GetAxis(0).GetLength();
|
||||
|
@ -450,6 +458,10 @@ namespace spades {
|
|||
modelNormalMatrix(program);
|
||||
modelNormalMatrix.SetValue(modelMatrix);
|
||||
|
||||
static GLProgramUniform modelOpacity("modelOpacity");
|
||||
modelOpacity(program);
|
||||
modelOpacity.SetValue(param.opacity);
|
||||
|
||||
if (param.depthHack) {
|
||||
device->DepthRange(0.f, 0.1f);
|
||||
}
|
||||
|
@ -531,6 +543,9 @@ namespace spades {
|
|||
for (size_t i = 0; i < params.size(); i++) {
|
||||
const client::ModelRenderParam ¶m = params[i];
|
||||
|
||||
if (param.ghost)
|
||||
continue;
|
||||
|
||||
// frustrum cull
|
||||
float rad = radius;
|
||||
rad *= param.matrix.GetAxis(0).GetLength();
|
||||
|
|
|
@ -79,11 +79,12 @@ namespace spades {
|
|||
|
||||
static void PreloadShaders(GLRenderer *);
|
||||
|
||||
void Prerender(std::vector<client::ModelRenderParam> params) override;
|
||||
void Prerender(std::vector<client::ModelRenderParam> params, bool ghostPass) override;
|
||||
|
||||
void RenderShadowMapPass(std::vector<client::ModelRenderParam> params) override;
|
||||
|
||||
void RenderSunlightPass(std::vector<client::ModelRenderParam> params) override;
|
||||
void RenderSunlightPass(std::vector<client::ModelRenderParam> params,
|
||||
bool ghostPass) override;
|
||||
|
||||
void RenderDynamicLightPass(std::vector<client::ModelRenderParam> params,
|
||||
std::vector<GLDynamicLight> lights) override;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include "SWModel.h"
|
||||
#include <Core/FileManager.h>
|
||||
#include <Core/VoxelModelLoader.h>
|
||||
#include <Core/IStream.h>
|
||||
|
||||
namespace spades {
|
||||
|
@ -56,33 +56,45 @@ namespace spades {
|
|||
if (z == 0 || z == (d - 1) || ((map >> (z - 1)) & 7ULL) != 7ULL ||
|
||||
(map1 & (1ULL << z)) == 0) {
|
||||
uint32_t col = m->GetColor(x, y, z);
|
||||
SPAssert(col != 0xddbeef);
|
||||
col = (col & 0xff00) | ((col & 0xff) << 16) | ((col & 0xff0000) >> 16);
|
||||
col |= z << 24;
|
||||
renderData.push_back(col);
|
||||
|
||||
uint32_t encodedColor;
|
||||
encodedColor =
|
||||
(col & 0xff00) | ((col & 0xff) << 16) | ((col & 0xff0000) >> 16);
|
||||
encodedColor |= z << 24;
|
||||
renderData.push_back(encodedColor);
|
||||
|
||||
auto material = static_cast<MaterialType>(col >> 24);
|
||||
|
||||
// store normal
|
||||
int nx = 0, ny = 0, nz = 0;
|
||||
for (int cx = -1; cx <= 1; cx++)
|
||||
for (int cy = -1; cy <= 1; cy++)
|
||||
for (int cz = -1; cz <= 1; cz++) {
|
||||
if (m->IsSolid(x + cx, y + cy, z + cz)) {
|
||||
nx -= cx;
|
||||
ny -= cy;
|
||||
nz -= cz;
|
||||
} else {
|
||||
nx += cx;
|
||||
ny += cy;
|
||||
nz += cz;
|
||||
uint32_t normal;
|
||||
|
||||
if (material == MaterialType::Emissive) {
|
||||
normal = 27;
|
||||
} else {
|
||||
int nx = 0, ny = 0, nz = 0;
|
||||
for (int cx = -1; cx <= 1; cx++)
|
||||
for (int cy = -1; cy <= 1; cy++)
|
||||
for (int cz = -1; cz <= 1; cz++) {
|
||||
if (m->IsSolid(x + cx, y + cy, z + cz)) {
|
||||
nx -= cx;
|
||||
ny -= cy;
|
||||
nz -= cz;
|
||||
} else {
|
||||
nx += cx;
|
||||
ny += cy;
|
||||
nz += cz;
|
||||
}
|
||||
}
|
||||
}
|
||||
nx = std::max(std::min(nx, 1), -1);
|
||||
ny = std::max(std::min(ny, 1), -1);
|
||||
nz = std::max(std::min(nz, 1), -1);
|
||||
nx++;
|
||||
ny++;
|
||||
nz++;
|
||||
renderData.push_back(nx + ny * 3 + nz * 9);
|
||||
nx = std::max(std::min(nx, 1), -1);
|
||||
ny = std::max(std::min(ny, 1), -1);
|
||||
nz = std::max(std::min(nz, 1), -1);
|
||||
nx++;
|
||||
ny++;
|
||||
nz++;
|
||||
normal = nx + ny * 3 + nz * 9;
|
||||
}
|
||||
|
||||
renderData.push_back(normal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,10 +131,8 @@ namespace spades {
|
|||
SWModel *SWModelManager::RegisterModel(const std::string &name) {
|
||||
auto it = models.find(name);
|
||||
if (it == models.end()) {
|
||||
std::unique_ptr<IStream> stream{FileManager::OpenForReading(name.c_str())};
|
||||
|
||||
Handle<VoxelModel> vm;
|
||||
vm.Set(VoxelModel::LoadKV6(stream.get()), false);
|
||||
vm.Set(VoxelModelLoader::Load(name.c_str()), false);
|
||||
|
||||
SWModel *model = CreateModel(vm);
|
||||
models.insert(std::make_pair(name, model));
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace spades {
|
|||
// int d = rawModel->GetDepth();
|
||||
|
||||
// evaluate brightness for each normals
|
||||
uint8_t brights[3 * 3 * 3];
|
||||
uint8_t brights[3 * 3 * 3 + 1];
|
||||
{
|
||||
auto lightVec = MakeVector3(0.f, -0.707f, -0.707f);
|
||||
float dot1 = Vector3::Dot(axis1, lightVec) * fastRSqrt(axis1.GetPoweredLength());
|
||||
|
@ -125,6 +125,9 @@ namespace spades {
|
|||
}
|
||||
}
|
||||
|
||||
// "emissive" material
|
||||
brights[27] = 255;
|
||||
|
||||
// compute center coord. for culling
|
||||
{
|
||||
auto center = origin;
|
||||
|
@ -228,7 +231,7 @@ namespace spades {
|
|||
if (color == 0)
|
||||
color = customColor;
|
||||
|
||||
SPAssert(normal < 27);
|
||||
SPAssert(normal < 28);
|
||||
int bright = brights[normal];
|
||||
#if ENABLE_SSE2
|
||||
if (lvl == SWFeatureLevel::SSE2) {
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "MainScreen.h"
|
||||
#include "MainScreenHelper.h"
|
||||
#include <Core/AutoLocker.h>
|
||||
#include <Core/FileManager.h>
|
||||
#include <Core/IStream.h>
|
||||
#include <Core/Settings.h>
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <Core/Mutex.h>
|
||||
#include <Core/RefCountedObject.h>
|
||||
#include <Core/TMPUtils.h>
|
||||
#include <ScriptBindings/ScriptManager.h>
|
||||
|
|
|
@ -21,14 +21,13 @@
|
|||
#include <curl/curl.h>
|
||||
#include <json/json.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "PackageUpdateManager.h"
|
||||
|
||||
#include <Core/AutoLocker.h>
|
||||
#include <Core/Debug.h>
|
||||
#include <Core/Exception.h>
|
||||
#include <Core/FileManager.h>
|
||||
#include <Core/Mutex.h>
|
||||
#include <Core/Settings.h>
|
||||
#include <Core/Strings.h>
|
||||
#include <Core/TMPUtils.h>
|
||||
|
@ -39,7 +38,7 @@ DEFINE_SPADES_SETTING(cl_checkForUpdates, "0");
|
|||
|
||||
namespace spades {
|
||||
namespace {
|
||||
Mutex globalMutex;
|
||||
std::recursive_mutex globalMutex;
|
||||
|
||||
PackageUpdateManager::VersionInfo ParseVersionInfo(const Json::Value &value) {
|
||||
if (!value.isObject()) {
|
||||
|
@ -88,21 +87,21 @@ namespace spades {
|
|||
PackageUpdateManager &m_packageUpdateManager;
|
||||
|
||||
void ReturnUnavailable() {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
SPAssert(m_packageUpdateManager.m_updateInfoReadyState == ReadyState::Loading);
|
||||
m_packageUpdateManager.m_updateInfoReadyState = ReadyState::Unavailable;
|
||||
|
||||
SPLog("Update info is not available for the package and/or the current platform.");
|
||||
}
|
||||
void ReturnError(const std::string &reason) {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
SPAssert(m_packageUpdateManager.m_updateInfoReadyState == ReadyState::Loading);
|
||||
m_packageUpdateManager.m_updateInfoReadyState = ReadyState::Error;
|
||||
|
||||
SPLog("Failed to check for update.: %s", reason.c_str());
|
||||
}
|
||||
void ReturnVersionInfo(const VersionInfo &info, const std::string &pageURL) {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
SPAssert(m_packageUpdateManager.m_updateInfoReadyState == ReadyState::Loading);
|
||||
m_packageUpdateManager.m_updateInfoReadyState = ReadyState::Loaded;
|
||||
m_packageUpdateManager.m_latestVersionInfo = info;
|
||||
|
@ -367,12 +366,12 @@ namespace spades {
|
|||
PackageUpdateManager::~PackageUpdateManager() {}
|
||||
|
||||
PackageUpdateManager::ReadyState PackageUpdateManager::GetUpdateInfoReadyState() {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
return m_updateInfoReadyState;
|
||||
}
|
||||
|
||||
bool PackageUpdateManager::IsUpdateAvailable() {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
|
||||
if (m_updateInfoReadyState != ReadyState::Loaded) {
|
||||
return false;
|
||||
|
@ -382,12 +381,12 @@ namespace spades {
|
|||
}
|
||||
|
||||
PackageUpdateManager::VersionInfo PackageUpdateManager::GetLatestVersionInfo() {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
return m_latestVersionInfo;
|
||||
}
|
||||
|
||||
std::string PackageUpdateManager::GetLatestVersionInfoPageURL() {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
|
||||
if (m_updateInfoReadyState != ReadyState::Loaded) {
|
||||
return std::string{};
|
||||
|
@ -397,7 +396,7 @@ namespace spades {
|
|||
}
|
||||
|
||||
void PackageUpdateManager::CheckForUpdate() {
|
||||
AutoLocker lock{&globalMutex};
|
||||
std::lock_guard<std::recursive_mutex> _lock{globalMutex};
|
||||
if (m_updateInfoReadyState == ReadyState::Loading) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <vector>
|
||||
|
||||
#include <Core/Math.h>
|
||||
#include <Core/Mutex.h>
|
||||
#include <Core/RefCountedObject.h>
|
||||
#include <ScriptBindings/ScriptManager.h>
|
||||
|
||||
|
|
|
@ -220,7 +220,11 @@ namespace spades {
|
|||
"bool depthHack",
|
||||
asOFFSET(ModelRenderParam, depthHack));
|
||||
manager->CheckError(r);
|
||||
|
||||
r = eng->RegisterObjectProperty("ModelRenderParam",
|
||||
"bool castShadow",
|
||||
asOFFSET(ModelRenderParam, castShadow));
|
||||
manager->CheckError(r);
|
||||
|
||||
r = eng->RegisterObjectBehaviour("DynamicLightParam",
|
||||
asBEHAVE_CONSTRUCT,
|
||||
"void f()",
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <Core/Exception.h>
|
||||
#include <Core/AutoLocker.h>
|
||||
#include <Core/FileManager.h>
|
||||
#include <Core/IStream.h>
|
||||
|
||||
|
@ -199,8 +198,8 @@ namespace spades {
|
|||
|
||||
ScriptContextHandle ScriptManager::GetContext() {
|
||||
SPADES_MARK_FUNCTION_DEBUG();
|
||||
AutoLocker locker(&contextMutex);
|
||||
if(contextFreeList.empty()){
|
||||
std::lock_guard<std::recursive_mutex> _lock{contextMutex};
|
||||
// no free context; create one
|
||||
Context *ctx = new Context();
|
||||
ctx->obj = engine->CreateContext();
|
||||
|
@ -223,13 +222,13 @@ namespace spades {
|
|||
ScriptContextHandle::ScriptContextHandle(ScriptManager::Context *ctx,
|
||||
ScriptManager *manager):
|
||||
manager(manager), obj(ctx){
|
||||
AutoLocker locker(&manager->contextMutex);
|
||||
std::lock_guard<std::recursive_mutex> _lock{manager->contextMutex};
|
||||
ctx->refCount++;
|
||||
}
|
||||
|
||||
ScriptContextHandle::ScriptContextHandle(const ScriptContextHandle& h) :
|
||||
manager(h.manager), obj(h.obj){
|
||||
AutoLocker locker(&manager->contextMutex);
|
||||
std::lock_guard<std::recursive_mutex> _lock{manager->contextMutex};
|
||||
obj->refCount++;
|
||||
}
|
||||
|
||||
|
@ -239,7 +238,7 @@ namespace spades {
|
|||
|
||||
void ScriptContextHandle::Release() {
|
||||
if(obj){
|
||||
AutoLocker locker(&manager->contextMutex);
|
||||
std::lock_guard<std::recursive_mutex> _lock{manager->contextMutex};
|
||||
obj->refCount--;
|
||||
if(obj->refCount == 0){
|
||||
// this context is no longer used;
|
||||
|
@ -258,7 +257,7 @@ namespace spades {
|
|||
|
||||
manager = h.manager;
|
||||
obj = h.obj;
|
||||
AutoLocker locker(&manager->contextMutex);
|
||||
std::lock_guard<std::recursive_mutex> _lock{manager->contextMutex};
|
||||
obj->refCount++;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#include <AngelScript/addons/scriptmathcomplex.h>
|
||||
#include <AngelScript/addons/scriptstdstring.h>
|
||||
#include <AngelScript/addons/weakref.h>
|
||||
#include <Core/Mutex.h>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
namespace spades {
|
||||
|
||||
|
@ -44,7 +44,7 @@ namespace spades {
|
|||
asIScriptContext *obj;
|
||||
int refCount;
|
||||
};
|
||||
Mutex contextMutex;
|
||||
std::recursive_mutex contextMutex;
|
||||
std::list<Context *> contextFreeList;
|
||||
|
||||
asIScriptEngine *engine;
|
||||
|
|
Loading…
Reference in New Issue