bool Texture2D::GetData(unsigned level, void* dest) const { if (!object_.name_ || !graphics_) { ATOMIC_LOGERROR("No texture created, can not get data"); return false; } #ifndef GL_ES_VERSION_2_0 if (!dest) { ATOMIC_LOGERROR("Null destination for getting data"); return false; } if (level >= levels_) { ATOMIC_LOGERROR("Illegal mip level for getting data"); return false; } if (graphics_->IsDeviceLost()) { ATOMIC_LOGWARNING("Getting texture data while device is lost"); return false; } if (multiSample_ > 1 && !autoResolve_) { ATOMIC_LOGERROR("Can not get data from multisampled texture without autoresolve"); return false; } if (resolveDirty_) graphics_->ResolveToTexture(const_cast<Texture2D*>(this)); graphics_->SetTextureForUpdate(const_cast<Texture2D*>(this)); if (!IsCompressed()) glGetTexImage(target_, level, GetExternalFormat(format_), GetDataType(format_), dest); else glGetCompressedTexImage(target_, level, dest); graphics_->SetTexture(0, 0); return true; #else // Special case on GLES: if the texture is a rendertarget, can make it current and use glReadPixels() if (usage_ == TEXTURE_RENDERTARGET) { graphics_->SetRenderTarget(0, const_cast<Texture2D*>(this)); // Ensure the FBO is current; this viewport is actually never rendered to graphics_->SetViewport(IntRect(0, 0, width_, height_)); glReadPixels(0, 0, width_, height_, GetExternalFormat(format_), GetDataType(format_), dest); return true; } ATOMIC_LOGERROR("Getting texture data not supported"); return false; #endif }
bool Geometry::SetDrawRange(PrimitiveType type, unsigned indexStart, unsigned indexCount, bool getUsedVertexRange) { if (!indexBuffer_ && !rawIndexData_) { ATOMIC_LOGERROR("Null index buffer and no raw index data, can not define indexed draw range"); return false; } if (indexBuffer_ && indexStart + indexCount > indexBuffer_->GetIndexCount()) { ATOMIC_LOGERROR("Illegal draw range " + String(indexStart) + " to " + String(indexStart + indexCount - 1) + ", index buffer has " + String(indexBuffer_->GetIndexCount()) + " indices"); return false; } primitiveType_ = type; indexStart_ = indexStart; indexCount_ = indexCount; // Get min.vertex index and num of vertices from index buffer. If it fails, use full range as fallback if (indexCount) { vertexStart_ = 0; vertexCount_ = vertexBuffers_[0] ? vertexBuffers_[0]->GetVertexCount() : 0; if (getUsedVertexRange && indexBuffer_) indexBuffer_->GetUsedVertexRange(indexStart_, indexCount_, vertexStart_, vertexCount_); } else { vertexStart_ = 0; vertexCount_ = 0; } return true; }
bool PListFile::BeginLoad(Deserializer& source) { if (GetName().Empty()) SetName(source.GetName()); XMLFile xmlFile(context_); if (!xmlFile.Load(source)) { ATOMIC_LOGERROR("Could not load property list"); return false; } XMLElement plistElem = xmlFile.GetRoot("plist"); if (!plistElem) { ATOMIC_LOGERROR("Invalid property list file"); return false; } root_.Clear(); XMLElement dictElem = plistElem.GetChild("dict"); if (!LoadDict(root_, dictElem)) return false; SetMemoryUse(source.GetSize()); return true; }
bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard) { if (start == 0 && count == indexCount_) return SetData(data); if (!data) { ATOMIC_LOGERROR("Null pointer for index buffer data"); return false; } if (!indexSize_) { ATOMIC_LOGERROR("Index size not defined, can not set index buffer data"); return false; } if (start + count > indexCount_) { ATOMIC_LOGERROR("Illegal range for setting new index buffer data"); return false; } if (!count) return true; if (shadowData_ && shadowData_.Get() + start * indexSize_ != data) memcpy(shadowData_.Get() + start * indexSize_, data, count * indexSize_); if (object_.ptr_) { if (dynamic_) { void* hwData = MapBuffer(start, count, discard); if (hwData) { memcpy(hwData, data, count * indexSize_); UnmapBuffer(); } else return false; } else { D3D11_BOX destBox; destBox.left = start * indexSize_; destBox.right = destBox.left + count * indexSize_; destBox.top = 0; destBox.bottom = 1; destBox.front = 0; destBox.back = 1; graphics_->GetImpl()->GetDeviceContext()->UpdateSubresource((ID3D11Buffer*)object_.ptr_, 0, &destBox, data, 0, 0); } } return true; }
bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard) { if (start == 0 && count == vertexCount_) return SetData(data); if (!data) { ATOMIC_LOGERROR("Null pointer for vertex buffer data"); return false; } if (!vertexSize_) { ATOMIC_LOGERROR("Vertex elements not defined, can not set vertex buffer data"); return false; } if (start + count > vertexCount_) { ATOMIC_LOGERROR("Illegal range for setting new vertex buffer data"); return false; } if (!count) return true; if (shadowData_ && shadowData_.Get() + start * vertexSize_ != data) memcpy(shadowData_.Get() + start * vertexSize_, data, count * vertexSize_); if (object_.ptr_) { if (graphics_->IsDeviceLost()) { ATOMIC_LOGWARNING("Vertex buffer data assignment while device is lost"); dataPending_ = true; return true; } void* hwData = MapBuffer(start, count, discard); if (hwData) { memcpy(hwData, data, count * vertexSize_); UnmapBuffer(); } else return false; } return true; }
void Cursor::ApplyOSCursorShape() { // Mobile platforms do not support applying OS cursor shapes: comment out to avoid log error messages #if !defined(ANDROID) && !defined(IOS) if (!osShapeDirty_ || !GetSubsystem<Input>()->IsMouseVisible() || GetSubsystem<SystemUI>()->GetCursor() != this) return; CursorShapeInfo& info = shapeInfos_[shape_]; // Remove existing SDL cursor if is not a system shape while we should be using those, or vice versa if (info.osCursor_ && info.systemDefined_ != useSystemShapes_) { SDL_FreeCursor(info.osCursor_); info.osCursor_ = 0; } // Create SDL cursor now if necessary if (!info.osCursor_) { // Create a system default shape if (useSystemShapes_ && info.systemCursor_ >= 0 && info.systemCursor_ < CS_MAX_SHAPES) { info.osCursor_ = SDL_CreateSystemCursor((SDL_SystemCursor)osCursorLookup[info.systemCursor_]); info.systemDefined_ = true; if (!info.osCursor_) ATOMIC_LOGERROR("Could not create system cursor"); } // Create from image else if (info.image_) { SDL_Surface* surface = info.image_->GetSDLSurface(info.imageRect_); if (surface) { info.osCursor_ = SDL_CreateColorCursor(surface, info.hotSpot_.x_, info.hotSpot_.y_); info.systemDefined_ = false; if (!info.osCursor_) ATOMIC_LOGERROR("Could not create cursor from image " + info.image_->GetName()); SDL_FreeSurface(surface); } } } if (info.osCursor_) SDL_SetCursor(info.osCursor_); osShapeDirty_ = false; #endif }
bool TextureCube::SetSize(int size, unsigned format, TextureUsage usage) { if (size <= 0) { ATOMIC_LOGERROR("Zero or negative cube texture size"); return false; } if (usage == TEXTURE_DEPTHSTENCIL) { ATOMIC_LOGERROR("Depth-stencil usage not supported for cube maps"); return false; } // Delete the old rendersurfaces if any for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i) { renderSurfaces_[i].Reset(); faceMemoryUse_[i] = 0; } usage_ = usage; if (usage == TEXTURE_RENDERTARGET) { for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i) { renderSurfaces_[i] = new RenderSurface(this); #ifdef ATOMIC_OPENGL renderSurfaces_[i]->target_ = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; #endif } // Nearest filtering and mipmaps disabled by default filterMode_ = FILTER_NEAREST; requestedLevels_ = 1; } if (usage == TEXTURE_RENDERTARGET) SubscribeToEvent(E_RENDERSURFACEUPDATE, ATOMIC_HANDLER(TextureCube, HandleRenderSurfaceUpdate)); else UnsubscribeFromEvent(E_RENDERSURFACEUPDATE); width_ = size; height_ = size; format_ = format; return Create(); }
void Player::SetCurrentScene(Scene* scene, Camera* camera) { Vector<SharedPtr<Scene>>::ConstIterator citr = loadedScenes_.Find(SharedPtr<Scene>(scene)); if (citr == loadedScenes_.End()) { ATOMIC_LOGERROR("Player::UnloadScene - unknown scene"); return; } currentScene_ = scene; if (!camera) { PODVector<Node*> cameraNodes; scene->GetChildrenWithComponent(cameraNodes, Camera::GetTypeStatic(), true); if (cameraNodes.Size()) { camera = cameraNodes[0]->GetComponent<Camera>(); } } viewport_->SetScene(scene); if (camera) viewport_->SetCamera(camera); }
void Player::UnloadScene(Scene* scene) { SharedPtr<Scene> keepalive(scene); if (currentScene_ == scene) { viewport_->SetScene(0); viewport_->SetCamera(0); currentScene_ = 0; } Vector<SharedPtr<Scene>>::ConstIterator citr = loadedScenes_.Find(keepalive); if (citr == loadedScenes_.End()) { ATOMIC_LOGERROR("Player::UnloadScene - unknown scene"); return; } VariantMap eventData; eventData[PlayerSceneUnload::P_SCENE] = scene; scene->SendEvent(E_PLAYERSCENEUNLOAD, eventData); loadedScenes_.Remove(keepalive); }
bool UnknownComponent::SaveXML(XMLElement& dest) const { if (dest.IsNull()) { ATOMIC_LOGERROR("Could not save " + GetTypeName() + ", null destination element"); return false; } if (!useXML_) ATOMIC_LOGWARNING("UnknownComponent loaded in binary or JSON mode, attributes will be empty for XML save"); // Write type and ID if (!dest.SetString("type", GetTypeName())) return false; if (!dest.SetInt("id", id_)) return false; for (unsigned i = 0; i < xmlAttributeInfos_.Size(); ++i) { XMLElement attrElem = dest.CreateChild("attribute"); attrElem.SetAttribute("name", xmlAttributeInfos_[i].name_); attrElem.SetAttribute("value", xmlAttributes_[i]); } return true; }
bool Geometry::SetDrawRange(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount, bool checkIllegal) { if (indexBuffer_) { // We can allow setting an illegal draw range now if the caller guarantees to resize / fill the buffer later if (checkIllegal && indexStart + indexCount > indexBuffer_->GetIndexCount()) { ATOMIC_LOGERROR("Illegal draw range " + String(indexStart) + " to " + String(indexStart + indexCount - 1) + ", index buffer has " + String(indexBuffer_->GetIndexCount()) + " indices"); return false; } } else if (!rawIndexData_) { indexStart = 0; indexCount = 0; } primitiveType_ = type; indexStart_ = indexStart; indexCount_ = indexCount; vertexStart_ = minVertex; vertexCount_ = vertexCount; return true; }
Variant ValueAnimation::SubstractAndMultiply(const Variant& value1, const Variant& value2, float t) const { switch (valueType_) { case VAR_FLOAT: return (value1.GetFloat() - value2.GetFloat()) * t; case VAR_VECTOR2: return (value1.GetVector2() - value2.GetVector2()) * t; case VAR_VECTOR3: return (value1.GetVector3() - value2.GetVector3()) * t; case VAR_VECTOR4: return (value1.GetVector4() - value2.GetVector4()) * t; case VAR_QUATERNION: return (value1.GetQuaternion() - value2.GetQuaternion()) * t; case VAR_COLOR: return (value1.GetColor() - value2.GetColor()) * t; case VAR_DOUBLE: return (value1.GetDouble() - value2.GetDouble()) * t; default: ATOMIC_LOGERROR("Invalid value type for spline interpolation's subtract and multiply operation"); return Variant::EMPTY; } }
bool PListFile::LoadValue(PListValue& value, const XMLElement& valueElem) { String valueType = valueElem.GetName(); if (valueType == "string") value.SetString(valueElem.GetValue()); else if (valueType == "real") value.SetFloat(ToFloat(valueElem.GetValue())); else if (valueType == "integer") value.SetInt(ToInt(valueElem.GetValue())); else if (valueType == "true") value.SetBool(true); else if (valueType == "false") value.SetBool(false); else if (valueType == "dict") { if (!LoadDict(value.ConvertToValueMap(), valueElem)) return false; } else if (valueType == "array") { if (!LoadArray(value.ConvertToValueVector(), valueElem)) return false; } else { ATOMIC_LOGERROR("Supported value type"); return false; } return true; }
float ValueAnimationInfo::CalculateScaledTime(float currentTime, bool& finished) const { float beginTime = animation_->GetBeginTime(); float endTime = animation_->GetEndTime(); switch (wrapMode_) { case WM_LOOP: { float span = endTime - beginTime; float time = fmodf(currentTime - beginTime, span); if (time < 0.0f) time += span; return beginTime + time; } case WM_ONCE: finished = (currentTime >= endTime); // Fallthrough case WM_CLAMP: return Clamp(currentTime, beginTime, endTime); default: ATOMIC_LOGERROR("Unsupported attribute animation wrap mode"); return beginTime; } }
void CustomGeometry::DefineGeometry(unsigned index, PrimitiveType type, unsigned numVertices, bool hasNormals, bool hasColors, bool hasTexCoords, bool hasTangents) { if (index > geometries_.Size()) { ATOMIC_LOGERROR("Geometry index out of bounds"); return; } geometryIndex_ = index; primitiveTypes_[index] = type; vertices_[index].Resize(numVertices); // If defining the first geometry, reset the element mask if (!index) elementMask_ = MASK_POSITION; if (hasNormals) elementMask_ |= MASK_NORMAL; if (hasColors) elementMask_ |= MASK_COLOR; if (hasTexCoords) elementMask_ |= MASK_TEXCOORD1; if (hasTangents) elementMask_ |= MASK_TANGENT; }
bool File::Open(PackageFile* package, const String& fileName) { if (!package) return false; const PackageEntry* entry = package->GetEntry(fileName); if (!entry) return false; bool success = OpenInternal(package->GetName(), FILE_READ, true); if (!success) { ATOMIC_LOGERROR("Could not open package file " + fileName); return false; } fileName_ = fileName; offset_ = entry->offset_; checksum_ = entry->checksum_; size_ = entry->size_; compressed_ = package->IsCompressed(); // Seek to beginning of package entry's file data SeekInternal(offset_); return true; }
bool IndexBuffer::SetData(const void* data) { if (!data) { ATOMIC_LOGERROR("Null pointer for index buffer data"); return false; } if (!indexSize_) { ATOMIC_LOGERROR("Index size not defined, can not set index buffer data"); return false; } if (shadowData_ && data != shadowData_.Get()) memcpy(shadowData_.Get(), data, indexCount_ * indexSize_); if (object_.ptr_) { if (dynamic_) { void* hwData = MapBuffer(0, indexCount_, true); if (hwData) { memcpy(hwData, data, indexCount_ * indexSize_); UnmapBuffer(); } else return false; } else { D3D11_BOX destBox; destBox.left = 0; destBox.right = indexCount_ * indexSize_; destBox.top = 0; destBox.bottom = 1; destBox.front = 0; destBox.back = 1; graphics_->GetImpl()->GetDeviceContext()->UpdateSubresource((ID3D11Buffer*)object_.ptr_, 0, &destBox, data, 0, 0); } } return true; }
bool IndexBuffer::GetUsedVertexRange(unsigned start, unsigned count, unsigned& minVertex, unsigned& vertexCount) { if (!shadowData_) { ATOMIC_LOGERROR("Used vertex range can only be queried from an index buffer with shadow data"); return false; } if (start + count > indexCount_) { ATOMIC_LOGERROR("Illegal index range for querying used vertices"); return false; } minVertex = M_MAX_UNSIGNED; unsigned maxVertex = 0; if (indexSize_ == sizeof(unsigned)) { unsigned* indices = ((unsigned*)shadowData_.Get()) + start; for (unsigned i = 0; i < count; ++i) { if (indices[i] < minVertex) minVertex = indices[i]; if (indices[i] > maxVertex) maxVertex = indices[i]; } } else { unsigned short* indices = ((unsigned short*)shadowData_.Get()) + start; for (unsigned i = 0; i < count; ++i) { if (indices[i] < minVertex) minVertex = indices[i]; if (indices[i] > maxVertex) maxVertex = indices[i]; } } vertexCount = maxVertex - minVertex + 1; return true; }
void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot) { if (shape < CS_NORMAL || shape >= CS_MAX_SHAPES) { ATOMIC_LOGERROR("Shape index out of bounds, can not define cursor shape"); return; } DefineShape(shapeNames[shape], image, imageRect, hotSpot); }
void* IndexBuffer::Lock(unsigned start, unsigned count, bool discard) { if (lockState_ != LOCK_NONE) { ATOMIC_LOGERROR("Index buffer already locked"); return 0; } if (!indexSize_) { ATOMIC_LOGERROR("Index size not defined, can not lock index buffer"); return 0; } if (start + count > indexCount_) { ATOMIC_LOGERROR("Illegal range for locking index buffer"); return 0; } if (!count) return 0; lockStart_ = start; lockCount_ = count; // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed if (object_.ptr_ && !shadowData_ && dynamic_) return MapBuffer(start, count, discard); else if (shadowData_) { lockState_ = LOCK_SHADOW; return shadowData_.Get() + start * indexSize_; } else if (graphics_) { lockState_ = LOCK_SCRATCH; lockScratchData_ = graphics_->ReserveScratchBuffer(count * indexSize_); return lockScratchData_; } else return 0; }
bool Geometry::SetVertexBuffer(unsigned index, VertexBuffer* buffer) { if (index >= vertexBuffers_.Size()) { ATOMIC_LOGERROR("Stream index out of bounds"); return false; } vertexBuffers_[index] = buffer; return true; }
bool CustomGeometry::SetMaterial(unsigned index, Material* material) { if (index >= batches_.Size()) { ATOMIC_LOGERROR("Material index out of bounds"); return false; } batches_[index].material_ = material; MarkNetworkUpdate(); return true; }
bool Geometry::SetNumVertexBuffers(unsigned num) { if (num >= MAX_VERTEX_STREAMS) { ATOMIC_LOGERROR("Too many vertex streams"); return false; } unsigned oldSize = vertexBuffers_.Size(); vertexBuffers_.Resize(num); return true; }
bool Texture3D::SetSize(int width, int height, int depth, unsigned format, TextureUsage usage) { if (width <= 0 || height <= 0 || depth <= 0) { ATOMIC_LOGERROR("Zero or negative 3D texture dimensions"); return false; } if (usage >= TEXTURE_RENDERTARGET) { ATOMIC_LOGERROR("Rendertarget or depth-stencil usage not supported for 3D textures"); return false; } usage_ = usage; width_ = width; height_ = height; depth_ = depth; format_ = format; return Create(); }
bool VertexBuffer::SetData(const void* data) { if (!data) { ATOMIC_LOGERROR("Null pointer for vertex buffer data"); return false; } if (!vertexSize_) { ATOMIC_LOGERROR("Vertex elements not defined, can not set vertex buffer data"); return false; } if (shadowData_ && data != shadowData_.Get()) memcpy(shadowData_.Get(), data, vertexCount_ * vertexSize_); if (object_.ptr_) { if (graphics_->IsDeviceLost()) { ATOMIC_LOGWARNING("Vertex buffer data assignment while device is lost"); dataPending_ = true; return true; } void* hwData = MapBuffer(0, vertexCount_, true); if (hwData) { memcpy(hwData, data, vertexCount_ * vertexSize_); UnmapBuffer(); } else return false; } dataLost_ = false; return true; }
unsigned File::Write(const void* data, unsigned size) { if (!IsOpen()) { // If file not open, do not log the error further here to prevent spamming the stderr stream return 0; } if (mode_ == FILE_READ) { ATOMIC_LOGERROR("File not opened for writing"); return 0; } if (!size) return 0; // Need to reassign the position due to internal buffering when transitioning from reading to writing if (writeSyncNeeded_) { fseek((FILE*)handle_, position_ + offset_, SEEK_SET); writeSyncNeeded_ = false; } if (fwrite(data, size, 1, (FILE*)handle_) != 1) { // Return to the position where the write began fseek((FILE*)handle_, position_ + offset_, SEEK_SET); ATOMIC_LOGERROR("Error while writing to file " + GetName()); return 0; } readSyncNeeded_ = true; position_ += size; if (position_ > size_) size_ = position_; return size; }
Variant ValueAnimation::SplineInterpolation(unsigned index1, unsigned index2, float scaledTime) { if (splineTangentsDirty_) UpdateSplineTangents(); const VAnimKeyFrame& keyFrame1 = keyFrames_[index1]; const VAnimKeyFrame& keyFrame2 = keyFrames_[index2]; float t = (scaledTime - keyFrame1.time_) / (keyFrame2.time_ - keyFrame1.time_); float tt = t * t; float ttt = t * tt; float h1 = 2.0f * ttt - 3.0f * tt + 1.0f; float h2 = -2.0f * ttt + 3.0f * tt; float h3 = ttt - 2.0f * tt + t; float h4 = ttt - tt; const Variant& v1 = keyFrame1.value_; const Variant& v2 = keyFrame2.value_; const Variant& t1 = splineTangents_[index1]; const Variant& t2 = splineTangents_[index2]; switch (valueType_) { case VAR_FLOAT: return v1.GetFloat() * h1 + v2.GetFloat() * h2 + t1.GetFloat() * h3 + t2.GetFloat() * h4; case VAR_VECTOR2: return v1.GetVector2() * h1 + v2.GetVector2() * h2 + t1.GetVector2() * h3 + t2.GetVector2() * h4; case VAR_VECTOR3: return v1.GetVector3() * h1 + v2.GetVector3() * h2 + t1.GetVector3() * h3 + t2.GetVector3() * h4; case VAR_VECTOR4: return v1.GetVector4() * h1 + v2.GetVector4() * h2 + t1.GetVector4() * h3 + t2.GetVector4() * h4; case VAR_QUATERNION: return v1.GetQuaternion() * h1 + v2.GetQuaternion() * h2 + t1.GetQuaternion() * h3 + t2.GetQuaternion() * h4; case VAR_COLOR: return v1.GetColor() * h1 + v2.GetColor() * h2 + t1.GetColor() * h3 + t2.GetColor() * h4; case VAR_DOUBLE: return v1.GetDouble() * h1 + v2.GetDouble() * h2 + t1.GetDouble() * h3 + t2.GetDouble() * h4; default: ATOMIC_LOGERROR("Invalid value type for spline interpolation"); return Variant::EMPTY; } }
void Context::ReleaseSDL() { --sdlInitCounter; if (sdlInitCounter == 0) { ATOMIC_LOGDEBUG("Quitting SDL"); SDL_QuitSubSystem(SDL_INIT_EVERYTHING); SDL_Quit(); } if (sdlInitCounter < 0) ATOMIC_LOGERROR("Too many calls to Context::ReleaseSDL()!"); }
void Context::ReleaseIK() { --ikInitCounter; if (ikInitCounter == 0) { ATOMIC_LOGDEBUG("De-initialising Inverse Kinematics library"); ik_log_unregister_listener(HandleIKLog); ik_log_deinit(); ik_memory_deinit(); } if (ikInitCounter < 0) ATOMIC_LOGERROR("Too many calls to Context::ReleaseIK()"); }
void CustomGeometry::BeginGeometry(unsigned index, PrimitiveType type) { if (index > geometries_.Size()) { ATOMIC_LOGERROR("Geometry index out of bounds"); return; } geometryIndex_ = index; primitiveTypes_[index] = type; vertices_[index].Clear(); // If beginning the first geometry, reset the element mask if (!index) elementMask_ = MASK_POSITION; }