Merge branch 'master' into block

master
otzade 2019-05-25 13:19:59 +03:00
commit a1def7e762
46 changed files with 544 additions and 311 deletions

View File

@ -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 */,

View File

@ -186,6 +186,8 @@ namespace spades {
Matrix4 matrix;
Vector3 customColor;
bool depthHack;
bool castShadow;
bool unlit;
}
class DynamicLightParam {

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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 \

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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 {

View File

@ -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"

View File

@ -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;
}
};
}

View File

@ -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>

View File

@ -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); }
}

View File

@ -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;
};
}

View File

@ -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) {

View File

@ -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>(); }
};
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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 &param = 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();

View File

@ -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;

View File

@ -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);

View File

@ -135,6 +135,7 @@ namespace spades {
void RenderDebugLines();
void RenderObjects();
void RenderGhosts();
void EnsureInitialized();
void EnsureSceneStarted();

View File

@ -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 &param = 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 &param = 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 &param = params[i];
if (param.ghost)
continue;
// frustrum cull
float rad = radius;
rad *= param.matrix.GetAxis(0).GetLength();

View File

@ -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;

View File

@ -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));

View File

@ -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) {

View File

@ -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>

View File

@ -24,7 +24,6 @@
#include <vector>
#include <memory>
#include <Core/Mutex.h>
#include <Core/RefCountedObject.h>
#include <Core/TMPUtils.h>
#include <ScriptBindings/ScriptManager.h>

View File

@ -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;
}

View File

@ -25,7 +25,6 @@
#include <vector>
#include <Core/Math.h>
#include <Core/Mutex.h>
#include <Core/RefCountedObject.h>
#include <ScriptBindings/ScriptManager.h>

View File

@ -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()",

View File

@ -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++;
}

View File

@ -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;