mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 08:21:24 +02:00
merge
This commit is contained in:
commit
47f978b86e
11 changed files with 181 additions and 43 deletions
140
examples/example/games/planky.js
Normal file
140
examples/example/games/planky.js
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
//
|
||||||
|
// planky.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Thijs Wenker on 5/2/14.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Pull blocks off the bottom and put them on the top using the grab.js script.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
|
||||||
|
const NUM_LAYERS = 16;
|
||||||
|
const BASE_DIMENSION = { x: 7, y: 2, z: 7 };
|
||||||
|
const BLOCKS_PER_LAYER = 3;
|
||||||
|
const BLOCK_SIZE = {x: 0.2, y: 0.1, z: 0.8};
|
||||||
|
const BLOCK_SPACING = BLOCK_SIZE.x / 3;
|
||||||
|
const GRAVITY = {x: 0, y: -2.8, z: 0};
|
||||||
|
const DENSITY = 2000;
|
||||||
|
const DAMPING_FACTOR = 0.98;
|
||||||
|
const ANGULAR_DAMPING_FACTOR = 0.8;
|
||||||
|
const SPAWN_DISTANCE = 3;
|
||||||
|
const BLOCK_YAW_OFFSET = 45;
|
||||||
|
const BUTTON_DIMENSIONS = {width: 49, height: 49};
|
||||||
|
|
||||||
|
var windowWidth = Window.innerWidth;
|
||||||
|
var size;
|
||||||
|
var pieces = [];
|
||||||
|
var ground = false;
|
||||||
|
var layerRotated = false;
|
||||||
|
|
||||||
|
function grabLowestJointY() {
|
||||||
|
var jointNames = MyAvatar.getJointNames();
|
||||||
|
var floorY = MyAvatar.position.y;
|
||||||
|
for (var jointName in jointNames) {
|
||||||
|
if (MyAvatar.getJointPosition(jointNames[jointName]).y < floorY) {
|
||||||
|
floorY = MyAvatar.getJointPosition(jointNames[jointName]).y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return floorY;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getButtonPosX() {
|
||||||
|
return windowWidth - ((BUTTON_DIMENSIONS.width / 2) + BUTTON_DIMENSIONS.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
var button = Overlays.addOverlay('image', {
|
||||||
|
x: getButtonPosX(),
|
||||||
|
y: 10,
|
||||||
|
width: BUTTON_DIMENSIONS.width,
|
||||||
|
height: BUTTON_DIMENSIONS.height,
|
||||||
|
imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg',
|
||||||
|
alpha: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function resetBlocks() {
|
||||||
|
pieces.forEach(function(piece) {
|
||||||
|
Entities.deleteEntity(piece);
|
||||||
|
});
|
||||||
|
pieces = [];
|
||||||
|
var avatarRot = Quat.fromPitchYawRollDegrees(0.0, MyAvatar.bodyYaw, 0.0);
|
||||||
|
basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(SPAWN_DISTANCE, Quat.getFront(avatarRot)));
|
||||||
|
basePosition.y = grabLowestJointY() - (BASE_DIMENSION.y / 2);
|
||||||
|
if (!ground) {
|
||||||
|
ground = Entities.addEntity({
|
||||||
|
type: 'Model',
|
||||||
|
modelURL: HIFI_PUBLIC_BUCKET + 'eric/models/woodFloor.fbx',
|
||||||
|
dimensions: BASE_DIMENSION,
|
||||||
|
position: basePosition,
|
||||||
|
rotation: avatarRot,
|
||||||
|
shapeType: 'box'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Entities.editEntity(ground, {position: basePosition, rotation: avatarRot});
|
||||||
|
}
|
||||||
|
var offsetRot = Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(0.0, BLOCK_YAW_OFFSET, 0.0));
|
||||||
|
basePosition.y += (BASE_DIMENSION.y / 2);
|
||||||
|
for (var layerIndex = 0; layerIndex < NUM_LAYERS; layerIndex++) {
|
||||||
|
var layerRotated = layerIndex % 2 === 0;
|
||||||
|
var offset = -(BLOCK_SPACING);
|
||||||
|
var layerRotation = Quat.fromPitchYawRollDegrees(0, layerRotated ? 0 : 90, 0.0);
|
||||||
|
for (var blockIndex = 0; blockIndex < BLOCKS_PER_LAYER; blockIndex++) {
|
||||||
|
var blockPositionXZ = BLOCK_SIZE.x * blockIndex - (BLOCK_SIZE.x * 3 / 2 - BLOCK_SIZE.x / 2);
|
||||||
|
var localTransform = Vec3.multiplyQbyV(offsetRot, {
|
||||||
|
x: (layerRotated ? blockPositionXZ + offset: 0),
|
||||||
|
y: (BLOCK_SIZE.y / 2) + (BLOCK_SIZE.y * layerIndex),
|
||||||
|
z: (layerRotated ? 0 : blockPositionXZ + offset)
|
||||||
|
});
|
||||||
|
pieces.push(Entities.addEntity({
|
||||||
|
type: 'Model',
|
||||||
|
modelURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/block.fbx',
|
||||||
|
shapeType: 'box',
|
||||||
|
name: 'JengaBlock' + ((layerIndex * BLOCKS_PER_LAYER) + blockIndex),
|
||||||
|
dimensions: BLOCK_SIZE,
|
||||||
|
position: {
|
||||||
|
x: basePosition.x + localTransform.x,
|
||||||
|
y: basePosition.y + localTransform.y,
|
||||||
|
z: basePosition.z + localTransform.z
|
||||||
|
},
|
||||||
|
rotation: Quat.multiply(layerRotation, offsetRot),
|
||||||
|
collisionsWillMove: true,
|
||||||
|
damping: DAMPING_FACTOR,
|
||||||
|
angularDamping: ANGULAR_DAMPING_FACTOR,
|
||||||
|
gravity: GRAVITY,
|
||||||
|
density: DENSITY
|
||||||
|
}));
|
||||||
|
offset += BLOCK_SPACING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||||
|
if (clickedOverlay === button) {
|
||||||
|
resetBlocks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
Overlays.deleteOverlay(button);
|
||||||
|
if (ground) {
|
||||||
|
Entities.deleteEntity(ground);
|
||||||
|
}
|
||||||
|
pieces.forEach(function(piece) {
|
||||||
|
Entities.deleteEntity(piece);
|
||||||
|
});
|
||||||
|
pieces = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUpdate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.update.connect(onUpdate)
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
|
@ -1173,8 +1173,10 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode ren
|
||||||
Camera *camera = Application::getInstance()->getCamera();
|
Camera *camera = Application::getInstance()->getCamera();
|
||||||
const glm::vec3 cameraPos = camera->getPosition();
|
const glm::vec3 cameraPos = camera->getPosition();
|
||||||
|
|
||||||
|
|
||||||
|
// HACK: comment this block which possibly change the near and break the rendering 5/6/2015
|
||||||
// Only tweak the frustum near far if it's not shadow
|
// Only tweak the frustum near far if it's not shadow
|
||||||
if (renderMode != RenderArgs::SHADOW_RENDER_MODE) {
|
/* if (renderMode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||||
// Set near clip distance according to skeleton model dimensions if first person and there is no separate head model.
|
// Set near clip distance according to skeleton model dimensions if first person and there is no separate head model.
|
||||||
if (shouldRenderHead(cameraPos, renderMode) || !getHead()->getFaceModel().getURL().isEmpty()) {
|
if (shouldRenderHead(cameraPos, renderMode) || !getHead()->getFaceModel().getURL().isEmpty()) {
|
||||||
renderFrustum->setNearClip(DEFAULT_NEAR_CLIP);
|
renderFrustum->setNearClip(DEFAULT_NEAR_CLIP);
|
||||||
|
@ -1184,7 +1186,7 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode ren
|
||||||
+ camera->getOrientation() * glm::vec3(0.0f, 0.0f, -clipDistance) - cameraPos);
|
+ camera->getOrientation() * glm::vec3(0.0f, 0.0f, -clipDistance) - cameraPos);
|
||||||
renderFrustum->setNearClip(clipDistance);
|
renderFrustum->setNearClip(clipDistance);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// Render the body's voxels and head
|
// Render the body's voxels and head
|
||||||
RenderArgs::RenderMode modelRenderMode = renderMode;
|
RenderArgs::RenderMode modelRenderMode = renderMode;
|
||||||
|
|
|
@ -190,8 +190,8 @@ void ApplicationOverlay::renderOverlay() {
|
||||||
Overlays& overlays = qApp->getOverlays();
|
Overlays& overlays = qApp->getOverlays();
|
||||||
|
|
||||||
_textureFov = glm::radians(_hmdUIAngularSize);
|
_textureFov = glm::radians(_hmdUIAngularSize);
|
||||||
auto deviceSize = Application::getInstance()->getDeviceSize();
|
glm::vec2 deviceSize = qApp->getCanvasSize();
|
||||||
_textureAspectRatio = (float)deviceSize.width() / (float)deviceSize.height();
|
_textureAspectRatio = (float)deviceSize.x / (float)deviceSize.y;
|
||||||
|
|
||||||
//Handle fading and deactivation/activation of UI
|
//Handle fading and deactivation/activation of UI
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ void ApplicationOverlay::renderOverlay() {
|
||||||
const float NEAR_CLIP = -10000;
|
const float NEAR_CLIP = -10000;
|
||||||
const float FAR_CLIP = 10000;
|
const float FAR_CLIP = 10000;
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glOrtho(0, deviceSize.width(), deviceSize.height(), 0, NEAR_CLIP, FAR_CLIP);
|
glOrtho(0, deviceSize.x, deviceSize.y, 0, NEAR_CLIP, FAR_CLIP);
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
|
||||||
|
@ -270,11 +270,11 @@ void ApplicationOverlay::displayOverlayTexture() {
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const glm::vec2 topLeft(-1, 1);
|
||||||
|
static const glm::vec2 bottomRight(1, -1);
|
||||||
|
static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||||
|
static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||||
static const glm::vec2 topLeft(-1, 1);
|
|
||||||
static const glm::vec2 bottomRight(1, -1);
|
|
||||||
static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
|
||||||
static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||||
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
|
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,22 +79,9 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args)
|
||||||
glm::vec4 yellowColor(1.0f, 1.0f, 0.2f, 1.0f);
|
glm::vec4 yellowColor(1.0f, 1.0f, 0.2f, 1.0f);
|
||||||
renderBoundingBox(entity, args, 0.3f, yellowColor);
|
renderBoundingBox(entity, args, 0.3f, yellowColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PhysicsEngine::physicsInfoIsActive(entity->getPhysicsInfo())) {
|
||||||
|
renderHoverDot(entity, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PhysicsEngine::physicsInfoIsActive(entity->getPhysicsInfo())) {
|
|
||||||
renderHoverDot(entity, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 position;
|
|
||||||
glm::quat rotation;
|
|
||||||
|
|
||||||
//
|
|
||||||
// XXX for future debugging
|
|
||||||
//
|
|
||||||
// if (PhysicsEngine::getBodyLocation(entity->getPhysicsInfo(), position, rotation)) {
|
|
||||||
// glm::vec3 positionOffset = glm::abs(position - entity->getPosition());
|
|
||||||
// if (positionOffset[0] > 0.001 || positionOffset[1] > 0.001 || positionOffset[2] > 0.001) {
|
|
||||||
// qDebug() << positionOffset[0] << positionOffset[1] << positionOffset[2];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,6 +278,11 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
|
||||||
return false; // hmm...
|
return false; // hmm...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_needsInitialSimulation) {
|
||||||
|
// the _model's offset will be wrong until _needsInitialSimulation is false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
assert(!_model->getCollisionURL().isEmpty());
|
assert(!_model->getCollisionURL().isEmpty());
|
||||||
|
|
||||||
if (_model->getURL().isEmpty()) {
|
if (_model->getURL().isEmpty()) {
|
||||||
|
|
|
@ -484,7 +484,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
|
||||||
meshPart._material->setShininess(material->shininess);
|
meshPart._material->setShininess(material->shininess);
|
||||||
meshPart._material->setOpacity(material->opacity);
|
meshPart._material->setOpacity(material->opacity);
|
||||||
}
|
}
|
||||||
qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count();
|
// qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count();
|
||||||
foreach(OBJFace face, faceGroup) {
|
foreach(OBJFace face, faceGroup) {
|
||||||
glm::vec3 v0 = vertices[face.vertexIndices[0]];
|
glm::vec3 v0 = vertices[face.vertexIndices[0]];
|
||||||
glm::vec3 v1 = vertices[face.vertexIndices[1]];
|
glm::vec3 v1 = vertices[face.vertexIndices[1]];
|
||||||
|
@ -526,7 +526,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
|
||||||
mesh.meshExtents.addPoint(vertex);
|
mesh.meshExtents.addPoint(vertex);
|
||||||
geometry.meshExtents.addPoint(vertex);
|
geometry.meshExtents.addPoint(vertex);
|
||||||
}
|
}
|
||||||
fbxDebugDump(geometry);
|
// fbxDebugDump(geometry);
|
||||||
} catch(const std::exception& e) {
|
} catch(const std::exception& e) {
|
||||||
qCDebug(modelformat) << "OBJ reader fail: " << e.what();
|
qCDebug(modelformat) << "OBJ reader fail: " << e.what();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
|
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
|
||||||
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
||||||
const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f;
|
const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f;
|
||||||
const float DEFAULT_NEAR_CLIP = 0.08f;
|
//const float DEFAULT_NEAR_CLIP = 0.08f;
|
||||||
|
const float DEFAULT_NEAR_CLIP = 0.25f;
|
||||||
const float DEFAULT_FAR_CLIP = (float)TREE_SCALE;
|
const float DEFAULT_FAR_CLIP = (float)TREE_SCALE;
|
||||||
|
|
||||||
class ViewFrustum {
|
class ViewFrustum {
|
||||||
|
|
|
@ -48,7 +48,6 @@ EntityMotionState::~EntityMotionState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) {
|
void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) {
|
||||||
/*
|
|
||||||
if (flags & EntityItem::DIRTY_POSITION) {
|
if (flags & EntityItem::DIRTY_POSITION) {
|
||||||
_sentPosition = _entity->getPosition();
|
_sentPosition = _entity->getPosition();
|
||||||
}
|
}
|
||||||
|
@ -61,7 +60,6 @@ void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) {
|
||||||
if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) {
|
if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) {
|
||||||
_sentAngularVelocity = _entity->getAngularVelocity();
|
_sentAngularVelocity = _entity->getAngularVelocity();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
|
@ -98,17 +96,9 @@ bool EntityMotionState::isMoving() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::isMovingVsServer() const {
|
bool EntityMotionState::isMovingVsServer() const {
|
||||||
// auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation()));
|
auto alignmentDot = glm::abs(glm::dot(_sentRotation, _entity->getRotation()));
|
||||||
// if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA ||
|
if (glm::distance(_sentPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA ||
|
||||||
// alignmentDot < IGNORE_ALIGNMENT_DOT) {
|
alignmentDot < IGNORE_ALIGNMENT_DOT) {
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
if (glm::length(_entity->getVelocity()) > IGNORE_LINEAR_VELOCITY_DELTA) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (glm::length(_entity->getAngularVelocity()) > IGNORE_ANGULAR_VELOCITY_DELTA) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -504,3 +494,12 @@ void EntityMotionState::setMotionType(MotionType motionType) {
|
||||||
ObjectMotionState::setMotionType(motionType);
|
ObjectMotionState::setMotionType(motionType);
|
||||||
resetMeasuredBodyAcceleration();
|
resetMeasuredBodyAcceleration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// virtual
|
||||||
|
QString EntityMotionState::getName() {
|
||||||
|
if (_entity) {
|
||||||
|
return _entity->getName();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,8 @@ public:
|
||||||
void resetMeasuredBodyAcceleration();
|
void resetMeasuredBodyAcceleration();
|
||||||
void measureBodyAcceleration();
|
void measureBodyAcceleration();
|
||||||
|
|
||||||
|
virtual QString getName();
|
||||||
|
|
||||||
friend class PhysicalEntitySimulation;
|
friend class PhysicalEntitySimulation;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -119,6 +119,8 @@ public:
|
||||||
virtual QUuid getSimulatorID() const = 0;
|
virtual QUuid getSimulatorID() const = 0;
|
||||||
virtual void bump() = 0;
|
virtual void bump() = 0;
|
||||||
|
|
||||||
|
virtual QString getName() { return ""; }
|
||||||
|
|
||||||
friend class PhysicsEngine;
|
friend class PhysicsEngine;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -294,7 +294,7 @@ GLuint TextureCache::getShadowDepthTextureID() {
|
||||||
|
|
||||||
/// Returns a texture version of an image file
|
/// Returns a texture version of an image file
|
||||||
gpu::TexturePointer TextureCache::getImageTexture(const QString & path) {
|
gpu::TexturePointer TextureCache::getImageTexture(const QString & path) {
|
||||||
QImage image(path);
|
QImage image = QImage(path).mirrored(false, true);
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB);
|
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB);
|
||||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB);
|
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB);
|
||||||
if (image.hasAlphaChannel()) {
|
if (image.hasAlphaChannel()) {
|
||||||
|
|
Loading…
Reference in a new issue