DX12) Part of the Constants buffer is cut off - c++

This is my Constant buffer for Object Drawing.
actually, gWorld and gOldWorld have correct values, but gCubemapOn, gMotionBlurOn, gRimLightOn values are going wrong.
gCubemapOn must be TRUE and it looks like, but actually that value is 65537.
and gRimLightOn must be TRUE, but as you see, actual value is FALSE.
The code below is how I use Constant Buffer.
template<typename Cnst>
class ConstantBuffer
{
public:
ConstantBuffer(ID3D12Device* device, UINT count, bool isConstant=true)
{
if (isConstant)
mByteSize = (sizeof(Cnst) + 255) & ~255;
else
mByteSize = sizeof(Cnst);
ThrowIfFailed(device->CreateCommittedResource(
&Extension::HeapProperties(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&Extension::BufferResourceDesc(D3D12_RESOURCE_DIMENSION_BUFFER, mByteSize * count),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr, IID_PPV_ARGS(&mUploadBuffer)));
ThrowIfFailed(mUploadBuffer->Map(0, nullptr, (void**)(&mData)));
}
ConstantBuffer(const ConstantBuffer& rhs) = delete;
ConstantBuffer& operator=(const ConstantBuffer& rhs) = delete;
virtual ~ConstantBuffer()
{
if (mUploadBuffer)
mUploadBuffer->Unmap(0, nullptr);
mData = nullptr;
}
D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress(int idx) const
{
return mUploadBuffer->GetGPUVirtualAddress() + idx * mByteSize;
}
void CopyData(int index, const Cnst& data)
{
memcpy(&mData[index * mByteSize], &data, sizeof(Cnst));
}
UINT GetByteSize() const
{
return mByteSize;
}
private:
ComPtr<ID3D12Resource> mUploadBuffer = nullptr;
BYTE* mData = nullptr;
UINT mByteSize = 0;
};
and this is how I Update Constant Buffer
void Pipeline::UpdateConstants()
{
UINT matOffset = 0;
for (int i = 0; i < mRenderObjects.size(); i++)
{
mObjectCB->CopyData(i, mRenderObjects[i]->GetObjectConstants());
mRenderObjects[i]->UpdateMatConstants(mMaterialCB.get(), matOffset);
matOffset += mRenderObjects[i]->GetMeshCount();
}
}
ObjectConstants GameObject::GetObjectConstants()
{
ObjectConstants objCnst = {};
if (mReflected)
{
objCnst.World = Matrix4x4::Transpose(Matrix4x4::Multiply(mWorld, mReflectMatrix));
objCnst.oldWorld = Matrix4x4::Transpose(Matrix4x4::Multiply(mOldWorld, mReflectMatrix));
}
else
{
objCnst.World = Matrix4x4::Transpose(mWorld);
objCnst.oldWorld = Matrix4x4::Transpose(mOldWorld);
}
objCnst.cubemapOn = mCubemapOn;
objCnst.motionBlurOn = mMotionBlurOn;
objCnst.rimLightOn = mRimLightOn;
return objCnst;
}
struct ObjectConstants
{
XMFLOAT4X4 World;
XMFLOAT4X4 oldWorld;
bool cubemapOn;
bool motionBlurOn;
bool rimLightOn;
};

I believe this is the same problem as seen here. HLSL bool is 4 bytes and C++ bool is 1 byte. If you declare your CPU struct as
struct ObjectConstants
{
XMFLOAT4X4 World;
XMFLOAT4X4 oldWorld;
int32_t cubemapOn;
int32_t motionBlurOn;
int32_t rimLightOn;
};
it should work.

Related

Rendering an obj mesh in Unreal Engine 4 with custom component presents visual artifacts

i'm trying to render an obj file by loading it through a custom component.
The model on the left is straigth out exported from blender, using a scale of 100, while the model on the right is from the same .obj file, but parsed drectly from code and rendered by building a custom Vertex Factory, Index Buffer and Position Buffer, with FMeshBatch::bWireframe = true :
As you can see, the model on the right renders with noticeable visual artifacts.
I started by creating a custom class that extends UPrimitiveComponent and a custom proxy for it that extends FPrimitiveComponent:
// UTestPrimitiveComponent.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/PrimitiveComponent.h"
#include "UTestPrimitiveComponent.generated.h"
class FPrimitiveSceneProxy;
class FObjectInitializer;
class UStaticMesh;
class FStaticMeshDescription;
struct FRawMesh;
USTRUCT()
struct FOBJMesh {
GENERATED_BODY()
TArray<FVector> vertices;
TArray<FVector> normals;
TArray<FVector2D> uvs;
TArray<int32> tex_indices; // Unused
TArray<uint32> vertex_indices;
TArray<int32> normals_indices; // Unused
};
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class RENDERINGPIPELINE_API UTestPrimitiveComponent :
public UPrimitiveComponent
{
GENERATED_BODY()
private:
FOBJMesh* TheMesh;
void ParseLine(FString& line, FRawMesh& Desc);
void ReadNormalFromLine(FString& line, FVector& normal);
void ReadUVFromLine(FString& line, FVector2D& uv);
void ReadVertexFromLine(FString& line, FVector& vertex);
void ReadFaceInfoFromLine(FString& element, FRawMesh& Desc);
public:
UTestPrimitiveComponent(const FObjectInitializer&);
void BeginPlay() override;
__forceinline FOBJMesh* GetMesh() { return TheMesh; }
FPrimitiveSceneProxy* CreateSceneProxy() override;
};
While this is the listing for both the proxy and the component:
#include "UTestPrimitiveComponent.h"
#include "Components/MeshComponent.h"
#include "GenericPlatform/GenericPlatformFile.h"
#include "Engine/StaticMesh.h"
#include "PrimitiveSceneProxy.h"
#include "StaticMeshDescription.h"
#include "Rendering/StaticMeshVertexBuffer.h"
#include "RawMesh.h"
#include "RHICommandList.h"
#include "PrimitiveSceneProxy.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#include "Misc/DefaultValueHelper.h"
#include "Containers/Array.h"
#include "EngineMinimal.h"
class UTestPrimitiveComponent;
template <typename T>
static FVertexBufferRHIRef CreateVertexBufferWithData(TArray<T>& data) {
FRHIResourceCreateInfo info;
auto size = sizeof (T)* data.Num();
FVertexBufferRHIRef buf = RHICreateVertexBuffer(size, BUF_Static | BUF_ShaderResource, info);
void* ptr = static_cast<void*>(RHILockVertexBuffer(buf, 0, size, RLM_WriteOnly));
FMemory::Memcpy(ptr, static_cast<void*>(data.GetData()), size);
RHIUnlockVertexBuffer(buf);
return buf;
}
struct FOBJIndexBuffer : public FIndexBuffer {
TArray<uint32> Indices;
virtual void InitRHI() override {
FRHIResourceCreateInfo info;
auto ElementSizeInBytes = sizeof(uint32);
auto ArraySize = ElementSizeInBytes * Indices.Num();
IndexBufferRHI = RHICreateIndexBuffer(ElementSizeInBytes, ArraySize, BUF_Static, info);
void* ptr = static_cast<void*>(RHILockIndexBuffer(IndexBufferRHI, 0, ArraySize, RLM_WriteOnly));
FMemory::Memcpy(ptr, static_cast<void*>(Indices.GetData()), ArraySize);
RHIUnlockIndexBuffer(IndexBufferRHI);
}
};
struct FOBJPositionBuffer : public FVertexBuffer {
TArray<FVector> Vertices;
FShaderResourceViewRHIRef PositionComponentSRV;
virtual void InitRHI() override {
FRHIResourceCreateInfo info;
VertexBufferRHI = CreateVertexBufferWithData(Vertices);
if (VertexBufferRHI)
{
PositionComponentSRV =
RHICreateShaderResourceView(FShaderResourceViewInitializer(VertexBufferRHI, PF_R32_FLOAT));
}
}
};
struct FOBJMeshBuffers : public FRenderResource {
struct FTangentData {
FPackedNormal X;
FPackedNormal Z;
public:
FTangentData(FPackedNormal InZ, FPackedNormal InX)
: X(InX), Z(InZ) {}
};
FVertexBuffer TexCoordsBuffer;
FVertexBuffer TangentsBuffer;
TArray<FVector2D> uvs;
TArray<FTangentData> Tangents;
FShaderResourceViewRHIRef TexCoordsBufferSRV;
FShaderResourceViewRHIRef TangentsBufferSRV;
virtual void InitRHI() override {
TexCoordsBuffer.VertexBufferRHI = CreateVertexBufferWithData(uvs);
if (TexCoordsBuffer.VertexBufferRHI) {
// PF_G16R16F if using half precision, todo when implementing full thing
TexCoordsBufferSRV = RHICreateShaderResourceView(FShaderResourceViewInitializer(TexCoordsBuffer.VertexBufferRHI, PF_G32R32F));
}
TangentsBuffer.VertexBufferRHI = CreateVertexBufferWithData(Tangents);
if (TangentsBuffer.VertexBufferRHI) {
// PF_R8G8B8A8_SNORM if using half precision, todo when implementing full thing
TangentsBufferSRV =
RHICreateShaderResourceView(FShaderResourceViewInitializer(TangentsBuffer.VertexBufferRHI, PF_R8G8B8A8_SNORM));
}
BeginInitResource(&TexCoordsBuffer);
BeginInitResource(&TangentsBuffer);
}
};
struct FOBJRenderData {
FOBJPositionBuffer OBJPositionBuffer;
FOBJMeshBuffers OBJMeshBuffers;
};
class OBJSceneProxy : public FPrimitiveSceneProxy {
public:
UMaterialInterface* Material;
FLocalVertexFactory VertexFactory;
FOBJMeshBuffers MeshBuffers;
FOBJPositionBuffer PositionBuffer;
FOBJIndexBuffer IndexBuffer;
UTestPrimitiveComponent* TheComponent;
OBJSceneProxy(UTestPrimitiveComponent* Component)
: FPrimitiveSceneProxy(Component, TEXT("OBJ Component")),
VertexFactory(GetScene().GetFeatureLevel(), "FObjSceneProxy"),
TheComponent(Component) {
IndexBuffer.Indices = TheComponent->GetMesh()->vertex_indices;
PositionBuffer.Vertices = TheComponent->GetMesh()->vertices;
MeshBuffers.uvs = Component->GetMesh()->uvs;
for (int i = 1; i < IndexBuffer.Indices.Num(); i++) {
// This block of code here is mostly wrong; Still, it shouldn't impact the rendering as much
// Blender y u start counting from 1
auto CurIndex = IndexBuffer.Indices[i] - 1;
auto PrevIndex = IndexBuffer.Indices[i - 1] - 1;
auto prevVertex = PositionBuffer.Vertices[PrevIndex];
auto curVertex = PositionBuffer.Vertices[CurIndex];
auto TangentRight = (curVertex - prevVertex).GetSafeNormal();
auto TangentFront = FVector::CrossProduct(TangentRight, curVertex.GetSafeNormal());
MeshBuffers.Tangents.Add(FOBJMeshBuffers::FTangentData(TangentFront, TangentRight));
}
BeginInitResource(&IndexBuffer);
BeginInitResource(&PositionBuffer);
BeginInitResource(&MeshBuffers);
InitFactory();
BeginInitResource(&VertexFactory);
Material = UMaterial::GetDefaultMaterial(MD_Surface);
}
virtual ~OBJSceneProxy()
{
IndexBuffer.ReleaseResource();
PositionBuffer.ReleaseResource();
MeshBuffers.TexCoordsBuffer.ReleaseResource();
MeshBuffers.TangentsBuffer.ReleaseResource();
MeshBuffers.ReleaseResource();
VertexFactory.ReleaseResource();
}
void InitFactory() {
struct FactoryParams {
FLocalVertexFactory* Factory;
FOBJMeshBuffers* MeshBuffers;
FOBJPositionBuffer* PositionBuffer;
} Params;
Params.Factory = &VertexFactory;
Params.PositionBuffer = &PositionBuffer;
Params.MeshBuffers = &MeshBuffers;
ENQUEUE_RENDER_COMMAND(OBJInitVertexFactory)([Params] (FRHICommandListImmediate& RHICmdList) {
FLocalVertexFactory::FDataType Data;
// Position stuff
Data.PositionComponent = FVertexStreamComponent(
Params.PositionBuffer,
0,
sizeof(FVector),
VET_Float3
);
Data.PositionComponentSRV = Params.PositionBuffer->PositionComponentSRV;
// Tex Coords stuff
Data.TextureCoordinatesSRV = Params.MeshBuffers->TexCoordsBufferSRV;
Data.TextureCoordinates.Add(FVertexStreamComponent(
&Params.MeshBuffers->TexCoordsBuffer,
0,
sizeof(FVector2D),
VET_Float4, // Doppio della dimensione (VET_Float2): Why?
EVertexStreamUsage::ManualFetch
));
// Tangents stuff
Data.TangentsSRV = Params.MeshBuffers->TangentsBufferSRV;
typedef FPackedNormal TangentType;
auto TangentElemType = VET_Short2;
auto TangentXOffset = STRUCT_OFFSET(FOBJMeshBuffers::FTangentData, X);
auto TangentZOffset = STRUCT_OFFSET(FOBJMeshBuffers::FTangentData, Z);
auto TangentSizeInBytes = sizeof(TangentType);
Data.TangentBasisComponents[0] = FVertexStreamComponent(
&Params.MeshBuffers->TangentsBuffer,
TangentXOffset,
TangentSizeInBytes,
TangentElemType,
EVertexStreamUsage::ManualFetch
);
Data.TangentBasisComponents[1] = FVertexStreamComponent(
&Params.MeshBuffers->TangentsBuffer,
TangentZOffset,
TangentSizeInBytes,
TangentElemType,
EVertexStreamUsage::ManualFetch
);
Data.LightMapCoordinateComponent = FVertexStreamComponent(
&Params.MeshBuffers->TexCoordsBuffer,
0,
sizeof(FVector2D),
VET_Float2,
EVertexStreamUsage::ManualFetch
);
FColorVertexBuffer::BindDefaultColorVertexBuffer(Params.Factory, Data,
FColorVertexBuffer::NullBindStride::FColorSizeForComponentOverride);
Params.Factory->SetData(Data);
Params.Factory->InitResource();
});
}
// (StartIndex + IndexCount) * IndexBuffer->GetStride()
void DrawStaticElements(FStaticPrimitiveDrawInterface* DrawInterface)
{
check(IsInRenderingThread());
FMaterialRenderProxy* Proxy = Material->GetRenderProxy();
FMeshBatch batch;
batch.bWireframe = true;
batch.VertexFactory = &VertexFactory;
batch.Type = PT_TriangleList;
batch.MaterialRenderProxy = Proxy;
batch.DepthPriorityGroup = SDPG_World;
batch.CastShadow = true;
batch.LODIndex = 0;
auto& BatchElement = batch.Elements[0];
BatchElement.IndexBuffer = &IndexBuffer;
// for i = FirstIndex to NumPrimitives ?
BatchElement.FirstIndex = 0;
BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3;
DrawInterface->DrawMesh(batch, MAX_FLT);
}
FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const
{
// Partially copied from StaticMeshRenderer.cpp
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = true;
Result.bRenderInMainPass = true;
Result.bVelocityRelevance = IsMovable() && Result.bOpaque && Result.bRenderInMainPass;
Result.bStaticRelevance = true;
Result.bDynamicRelevance = false;
return Result;
}
};
UTestPrimitiveComponent::UTestPrimitiveComponent(const FObjectInitializer& ObjectInitializer) :
UPrimitiveComponent(ObjectInitializer) {
UActorComponent::PrimaryComponentTick.bCanEverTick = true;
TheMesh = new FOBJMesh();
FString result;
auto gamePath = FPaths::ProjectContentDir();
auto fullPath = FPaths::Combine(gamePath, TEXT("RawContent"), TEXT("cube.obj"));
FFileHelper::LoadFileToString(result, *fullPath);
FRawMesh meshInfo;
TArray<FString> lines;
result.ParseIntoArrayLines(lines);
for (auto line : lines) {
ParseLine(line, meshInfo);
}
}
void UTestPrimitiveComponent::BeginPlay()
{
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red,
FString::Printf(TEXT("Vertices: %d, UVs: %d, Normals: %d"), TheMesh->vertices.Num(), TheMesh->uvs.Num(), TheMesh->normals.Num()));
GEngine->AddOnScreenDebugMessage(2, 5.0f, FColor::Red,
FString::Printf(TEXT("VIndices: %d, UVIndices: %d, NIndices: %d"), TheMesh->vertex_indices.Num(), TheMesh->tex_indices.Num(), TheMesh->normals_indices.Num()));
}
FPrimitiveSceneProxy* UTestPrimitiveComponent::CreateSceneProxy()
{
return (FPrimitiveSceneProxy*)(new OBJSceneProxy(this));
}
void UTestPrimitiveComponent::ParseLine(FString& line, FRawMesh& Desc)
{
if (line[0] == 'v') {
if (line[1] == 'n') {
// It is a normal
line.RemoveFromStart(TEXT("vn "));
FVector normal;
ReadNormalFromLine(line, normal);
TheMesh->normals.Add(normal);
}
else if (line[1] == 't') {
// It is an uv vertex
line.RemoveFromStart(TEXT("vt "));
FVector2D uv;
ReadUVFromLine(line, uv);
TheMesh->uvs.Add(uv);
}
else {
// It is a vertex
line.RemoveFromStart(TEXT("v "));
FVector vertex;
ReadVertexFromLine(line, vertex);
TheMesh->vertices.Add(vertex);
}
}
else if (line[0] == 'f') {
line.RemoveFromStart("f ");
TArray<FString> elements;
line.ParseIntoArray(elements, TEXT(" "));
for (int i = 0; i < elements.Num(); i++) {
ReadFaceInfoFromLine(elements[i], Desc);
}
}
// Ignore the line if it's a comment, a usrlib/matlib/other stuff directive
else return;
}
void UTestPrimitiveComponent::ReadNormalFromLine(FString& line, FVector& normal)
{
TArray<FString> elements;
line.ParseIntoArray(elements, TEXT(" "));
FDefaultValueHelper::ParseFloat(elements[0], normal.X);
FDefaultValueHelper::ParseFloat(elements[1], normal.Y);
FDefaultValueHelper::ParseFloat(elements[2], normal.Z);
}
void UTestPrimitiveComponent::ReadUVFromLine(FString& line, FVector2D& uv)
{
TArray<FString> elements;
line.ParseIntoArray(elements, TEXT(" "));
FDefaultValueHelper::ParseFloat(elements[0], uv.X);
FDefaultValueHelper::ParseFloat(elements[1], uv.Y);
if (elements.Num() == 3) {
// We have a w! Ignore, UE4 does not support it
// FDefaultValueHelper::ParseFloat(elements[2], uv.Z);
}
}
void UTestPrimitiveComponent::ReadVertexFromLine(FString& line, FVector& vertex)
{
TArray<FString> elements;
line.ParseIntoArray(elements, TEXT(" "));
FDefaultValueHelper::ParseFloat(elements[0], vertex.X);
FDefaultValueHelper::ParseFloat(elements[1], vertex.Y);
FDefaultValueHelper::ParseFloat(elements[2], vertex.Z);
if (elements.Num() == 4) {
// We have a w! UE4 does not support it
// FDefaultValueHelper::ParseFloat(elements[3], vertex.W);
}
}
void UTestPrimitiveComponent::ReadFaceInfoFromLine(FString& element, FRawMesh& Desc)
{
int vertex_index;
// Splitting the vi/ui/ni triplet
TArray<FString> tripletString;
element.ParseIntoArray(tripletString, TEXT("/"));
FDefaultValueHelper::ParseInt(tripletString[0], vertex_index);
TheMesh->vertex_indices.Add(vertex_index);
/* UE4 does not use this stuff
if (tripletString.Num() > 1) {
FDefaultValueHelper::ParseInt(tripletString[1], uv_index);
TheMesh->tex_indices.Add(uv_index);
}
if (tripletString.Num() > 2) {
FDefaultValueHelper::ParseInt(tripletString[2], normal_index);
TheMesh->normals_indices.Add(normal_index);
}
*/
}
I have absolutely no idea why the rendering is broken, could anyone help me?
Solved, the issue was that Blender starts counting vertices from 1 (so yes, the problem was how i was reading the obj file)

Is this template specialization or a declaration (or something else altogether)?

I came across this code in Nvidia's CUDA Samples n-body simulation:
template <> NBodyDemo<double> *NBodyDemo<double>::m_singleton = 0;
template <> NBodyDemo<float> *NBodyDemo<float>::m_singleton = 0;
Is this code declaring pointers? If that is the case why the template<> then.
I could not figure out what these two lines are for.
Also, the ctor and dtor of the class are private; one instantiates this class using the Create() method. This is very unusual in my experience and I was hoping to gain some insight into the reason behind this style of coding.
Copyright notice
/*
* Copyright 1993-2015 NVIDIA Corporation. All rights reserved.
*
* Please refer to the NVIDIA end user license agreement (EULA) associated
* with this source code for terms and conditions that govern your use of
* this software. Any use, reproduction, disclosure, or distribution of
* this software and related documentation outside the terms of the EULA
* is strictly prohibited.
*
*/
Class definition
template <typename T>
class NBodyDemo
{
public:
static void Create()
{
m_singleton = new NBodyDemo;
}
static void Destroy()
{
delete m_singleton;
}
static void init(int numBodies, int numDevices, int blockSize,
bool usePBO, bool useHostMem, bool useCpu)
{
m_singleton->_init(numBodies, numDevices, blockSize, usePBO, useHostMem, useCpu);
}
static void reset(int numBodies, NBodyConfig config)
{
m_singleton->_reset(numBodies, config);
}
static void selectDemo(int index)
{
m_singleton->_selectDemo(index);
}
static bool compareResults(int numBodies)
{
return m_singleton->_compareResults(numBodies);
}
static void runBenchmark(int iterations)
{
m_singleton->_runBenchmark(iterations);
}
static void updateParams()
{
m_singleton->m_nbody->setSoftening(activeParams.m_softening);
m_singleton->m_nbody->setDamping(activeParams.m_damping);
}
static void updateSimulation()
{
m_singleton->m_nbody->update(activeParams.m_timestep);
}
static void display()
{
m_singleton->m_renderer->setSpriteSize(activeParams.m_pointSize);
if (useHostMem)
{
// This event sync is required because we are rendering from the host memory that CUDA is
// writing. If we don't wait until CUDA is done updating it, we will render partially
// updated data, resulting in a jerky frame rate.
if (!useCpu)
{
cudaEventSynchronize(hostMemSyncEvent);
}
m_singleton->m_renderer->setPositions(
m_singleton->m_nbody->getArray(BODYSYSTEM_POSITION),
m_singleton->m_nbody->getNumBodies());
}
else
{
m_singleton->m_renderer->setPBO(m_singleton->m_nbody->getCurrentReadBuffer(),
m_singleton->m_nbody->getNumBodies(),
(sizeof(T) > 4));
}
// display particles
m_singleton->m_renderer->display(displayMode);
}
static void getArrays(T *pos, T *vel)
{
T *_pos = m_singleton->m_nbody->getArray(BODYSYSTEM_POSITION);
T *_vel = m_singleton->m_nbody->getArray(BODYSYSTEM_VELOCITY);
memcpy(pos, _pos, m_singleton->m_nbody->getNumBodies() * 4 * sizeof(T));
memcpy(vel, _vel, m_singleton->m_nbody->getNumBodies() * 4 * sizeof(T));
}
static void setArrays(const T *pos, const T *vel)
{
if (pos != m_singleton->m_hPos)
{
memcpy(m_singleton->m_hPos, pos, numBodies * 4 * sizeof(T));
}
if (vel != m_singleton->m_hVel)
{
memcpy(m_singleton->m_hVel, vel, numBodies * 4 * sizeof(T));
}
m_singleton->m_nbody->setArray(BODYSYSTEM_POSITION, m_singleton->m_hPos);
m_singleton->m_nbody->setArray(BODYSYSTEM_VELOCITY, m_singleton->m_hVel);
if (!benchmark && !useCpu && !compareToCPU)
{
m_singleton->_resetRenderer();
}
}
private:
static NBodyDemo *m_singleton;
BodySystem<T> *m_nbody;
BodySystemCUDA<T> *m_nbodyCuda;
BodySystemCPU<T> *m_nbodyCpu;
ParticleRenderer *m_renderer;
T *m_hPos;
T *m_hVel;
float *m_hColor;
private:
NBodyDemo()
: m_nbody(0),
m_nbodyCuda(0),
m_nbodyCpu(0),
m_renderer(0),
m_hPos(0),
m_hVel(0),
m_hColor(0)
{
}
~NBodyDemo()
{
if (m_nbodyCpu)
{
delete m_nbodyCpu;
}
if (m_nbodyCuda)
{
delete m_nbodyCuda;
}
if (m_hPos)
{
delete [] m_hPos;
}
if (m_hVel)
{
delete [] m_hVel;
}
if (m_hColor)
{
delete [] m_hColor;
}
sdkDeleteTimer(&demoTimer);
if (!benchmark && !compareToCPU)
delete m_renderer;
}
void _init(int numBodies, int numDevices, int blockSize,
bool bUsePBO, bool useHostMem, bool useCpu)
{
if (useCpu)
{
m_nbodyCpu = new BodySystemCPU<T>(numBodies);
m_nbody = m_nbodyCpu;
m_nbodyCuda = 0;
}
else
{
m_nbodyCuda = new BodySystemCUDA<T>(numBodies, numDevices, blockSize, bUsePBO, useHostMem);
m_nbody = m_nbodyCuda;
m_nbodyCpu = 0;
}
// allocate host memory
m_hPos = new T[numBodies*4];
m_hVel = new T[numBodies*4];
m_hColor = new float[numBodies*4];
m_nbody->setSoftening(activeParams.m_softening);
m_nbody->setDamping(activeParams.m_damping);
if (useCpu)
{
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
}
else
{
checkCudaErrors(cudaEventCreate(&startEvent));
checkCudaErrors(cudaEventCreate(&stopEvent));
checkCudaErrors(cudaEventCreate(&hostMemSyncEvent));
}
if (!benchmark && !compareToCPU)
{
m_renderer = new ParticleRenderer;
_resetRenderer();
}
sdkCreateTimer(&demoTimer);
sdkStartTimer(&demoTimer);
}
void _reset(int numBodies, NBodyConfig config)
{
if (tipsyFile == "")
{
randomizeBodies(config, m_hPos, m_hVel, m_hColor,
activeParams.m_clusterScale,
activeParams.m_velocityScale,
numBodies, true);
setArrays(m_hPos, m_hVel);
}
else
{
m_nbody->loadTipsyFile(tipsyFile);
::numBodies = m_nbody->getNumBodies();
}
}
void _resetRenderer()
{
if (fp64)
{
float color[4] = { 0.4f, 0.8f, 0.1f, 1.0f};
m_renderer->setBaseColor(color);
}
else
{
float color[4] = { 1.0f, 0.6f, 0.3f, 1.0f};
m_renderer->setBaseColor(color);
}
m_renderer->setColors(m_hColor, m_nbody->getNumBodies());
m_renderer->setSpriteSize(activeParams.m_pointSize);
}
void _selectDemo(int index)
{
assert(index < numDemos);
activeParams = demoParams[index];
camera_trans[0] = camera_trans_lag[0] = activeParams.m_x;
camera_trans[1] = camera_trans_lag[1] = activeParams.m_y;
camera_trans[2] = camera_trans_lag[2] = activeParams.m_z;
reset(numBodies, NBODY_CONFIG_SHELL);
sdkResetTimer(&demoTimer);
}
bool _compareResults(int numBodies)
{
assert(m_nbodyCuda);
bool passed = true;
m_nbody->update(0.001f);
{
m_nbodyCpu = new BodySystemCPU<T>(numBodies);
m_nbodyCpu->setArray(BODYSYSTEM_POSITION, m_hPos);
m_nbodyCpu->setArray(BODYSYSTEM_VELOCITY, m_hVel);
m_nbodyCpu->update(0.001f);
T *cudaPos = m_nbodyCuda->getArray(BODYSYSTEM_POSITION);
T *cpuPos = m_nbodyCpu->getArray(BODYSYSTEM_POSITION);
T tolerance = 0.0005f;
for (int i = 0; i < numBodies; i++)
{
if (fabs(cpuPos[i] - cudaPos[i]) > tolerance)
{
passed = false;
printf("Error: (host)%f != (device)%f\n", cpuPos[i], cudaPos[i]);
}
}
}
if (passed)
{
printf(" OK\n");
}
return passed;
}
void _runBenchmark(int iterations)
{
// once without timing to prime the device
if (!useCpu)
{
m_nbody->update(activeParams.m_timestep);
}
if (useCpu)
{
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
}
else
{
checkCudaErrors(cudaEventRecord(startEvent, 0));
}
for (int i = 0; i < iterations; ++i)
{
m_nbody->update(activeParams.m_timestep);
}
float milliseconds = 0;
if (useCpu)
{
sdkStopTimer(&timer);
milliseconds = sdkGetTimerValue(&timer);
sdkStartTimer(&timer);
}
else
{
checkCudaErrors(cudaEventRecord(stopEvent, 0));
checkCudaErrors(cudaEventSynchronize(stopEvent));
checkCudaErrors(cudaEventElapsedTime(&milliseconds, startEvent, stopEvent));
}
double interactionsPerSecond = 0;
double gflops = 0;
computePerfStats(interactionsPerSecond, gflops, milliseconds, iterations);
printf("%d bodies, total time for %d iterations: %.3f ms\n",
numBodies, iterations, milliseconds);
printf("= %.3f billion interactions per second\n", interactionsPerSecond);
printf("= %.3f %s-precision GFLOP/s at %d flops per interaction\n", gflops,
(sizeof(T) > 4) ? "double" : "single", flopsPerInteraction);
}
};
NBodyDemo is a class template because it uses the parameter T in some members and functions, like BodySystem<T> *m_nbody; or setArrays(const T *pos,...)
m_singleton is a static pointer of type NBodyDemo. "static" means it will be shared by all instances with the same parameter T.
template <> NBodyDemo<double> *NBodyDemo<double>::m_singleton = 0;
initializes m_singleton for the "T = double" specialization.
template <> is required for templates outside of its declaration scope.

c++ can not get value from map

I have implemented a serializer to send data over network. And I have implemented a system that can deserialize primitive data, string, map(string, string), map(string, float), but the error happens with map(string, int) when the deserialized map is used to fetch the value from key. In the debugger I can see that map receive correct value but when I'm trying to get data, I get an error "std::out_of_range at memory location".
Here is my code
#include <stdint.h>
#include <memory>
#include <string>
#include <map>
#include <algorithm>
#define STREAM_ENDIANNESS 0
#define PLATFORM_ENDIANNESS 0
using namespace std;
class OutputMemoryStream
{
void ReallocBuffer(uint32_t inNewLength)
{
mBuffer = static_cast<char*>(std::realloc(mBuffer, inNewLength));
mCapacity = inNewLength;
}
char* mBuffer = nullptr;
uint32_t mHead;
uint32_t mCapacity;
public:
OutputMemoryStream() : mHead(0) { ReallocBuffer(32); }
~OutputMemoryStream()
{
if (mBuffer) { mBuffer = nullptr; }
}
char* GetBufferPtr() const { return mBuffer; }
uint32_t GetLength() const { return mHead; }
void Write(const void* inData, size_t inByteCount)
{
//make sure we have space...
uint32_t resultHead = mHead + static_cast<uint32_t>(inByteCount);
if (resultHead > mCapacity)
{
ReallocBuffer(std::max(mCapacity * 2, resultHead));
}
//copy into buffer at head
std::memcpy(mBuffer + mHead, inData, inByteCount);
//increment head for next write
mHead = resultHead;
}
template< typename T > void Write(T inData)
{
static_assert(std::is_arithmetic< T >::value || std::is_enum< T >::value, "Generic Write only supports primitive data types");
if (STREAM_ENDIANNESS == PLATFORM_ENDIANNESS)
{
Write(&inData, sizeof(inData));
}
else { }
}
template< typename T >
void Write(const std::map< string, T >& inMap)
{
uint32_t elementCount = inMap.size();
Write(elementCount);
for (std::pair<string, T> element : inMap)
{
Write(element.first);
Write(element.second);
}
}
void Write(const std::string& inString)
{
size_t elementCount = inString.size();
Write(elementCount + 1);
Write(inString.data(), (elementCount + 1) * sizeof(char));
}
};
class InputMemoryStream
{
private:
char* mBuffer;
uint32_t mHead;
uint32_t mCapacity;
public:
InputMemoryStream() {}
InputMemoryStream(char* inBuffer, uint32_t inByteCount) : mBuffer(inBuffer), mCapacity(inByteCount), mHead(0) { }
~InputMemoryStream()
{
if (mBuffer) { mBuffer = nullptr; }
}
uint32_t GetRemainingDataSize() const
{
return mCapacity - mHead;
}
void Read(void* outData, uint32_t inByteCount)
{
uint32_t resultHead = mHead + inByteCount;
if (resultHead > mCapacity)
{
//handle error, no data to read!
//...
}
std::memcpy(outData, mBuffer + mHead, inByteCount);
mHead = resultHead;
}
template< typename T > void Read(T& outData)
{
static_assert(std::is_arithmetic< T >::value || std::is_enum< T >::value, "Generic Read only supports primitive data types");
Read(&outData, sizeof(outData));
}
template<typename T1>
void Read(std::map<string, T1> &mapP)
{
size_t elemenCount;
Read(elemenCount);
for (int i = 0; i < elemenCount; i++)
{
string key; T1 value;
Read(key);
Read(value);
std::pair<string, T1> pair(key, value);
mapP.insert(pair);
}
}
void Read(string &outString)
{
size_t strSize;
Read(strSize);
outString.resize(strSize);
for (int i = 0; i < strSize; i++)
{
Read(&outString[i], 1);
}
}
};
class ServerObject
{
OutputMemoryStream outStream;
InputMemoryStream inStream;
map<std::string, int> mapInt;
public:
ServerObject() {};
ServerObject(char* byteArray, int byteCount)
{
InputMemoryStream inStream(byteArray, byteCount);
Deserialize(inStream);
}
~ServerObject() {};
void Serialize()
{
outStream.Write(mapInt);
}
void Deserialize(InputMemoryStream inStream)
{
inStream.Read(mapInt);
}
OutputMemoryStream GetOutStream()
{
return outStream;
}
int GetInt(string key)
{
return mapInt.at(key);
}
void PutInt(string key, int value)
{
mapInt.insert(std::pair<string, int>(key, value));
}
};
int main()
{
ServerObject * so = new ServerObject();
so->PutInt("test", 10);
so->Serialize();
ServerObject * so1 = new ServerObject(so->GetOutStream().GetBufferPtr(), so->GetOutStream().GetLength());
int i = so1->GetInt("test");
system("pause>NULL");
return 0;
}
Your void Write(const std::string& inString) function of OutputMemoryStream should not store additional byte of buffer for null terminator because std::string will not contain null terminator but if you use c_str(), a null terminator will be included in the return from this method. Don't get confused with the internal structure of the memory. std::string stores the length of the string in its member variable so there is no need of null terminator. The function should be as shown below.
void Write(const std::string& inString)
{
size_t elementCount = inString.size();
Write(elementCount);
Write(inString.data(), elementCount * sizeof(char));
}

Exception Error C++ //Visual Studio [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
So im creating an engine from scrath(learnign purposes).
And when i test my TArray i get an Execption thrown in my Memory.h file. This happens only when im trying to test the TArray
Here is my code for TArray.h
#pragma once
#include "Memory/DynamicLinearStackAllocator.h"
template <typename T, typename Allocator = DynamicLinearStackAllocator>
class TArray
{
private:
Allocator m_Allocator;
uint32 m_ElementCount;
public:
FORCEINLINE TArray()
{
}
FORCEINLINE ~TArray()
{
m_Allocator.Destroy();
}
FORCEINLINE TArray(const uint32 InElementCount)
{
m_Allocator.Resize<T>(InElementCount, m_ElementCount);
m_ElementCount = InElementCount;
}
FORCEINLINE void Add(const T &InValue)
{
}
FORCEINLINE T* GetData() const { return m_Allocator.GetAllocator<T>(); }
FORCEINLINE uint32 Num() const
{
return m_ElementCount;
}
FORCEINLINE T& operator[](uint32 InElementIndex) const
{
check(m_ElementCount > InElementIndex);
return GetData()[InElementIndex];
}
};
namespace Tests
{
FORCEINLINE void TestArrays()
{
{
TArray<float> data(10);
check(data.Num() == 10);
for(uint32 i = 0; i < data.Num(); i++)
{
data[i] = 2.0f;
}
check(data[0] == 2.0f);
}
{
TArray<uint32> data(5);
data[0] = 10;
data[1] = 5;
check(data.Num() == 5);
check(data[0] == 10);
check(data[1] == 5);
}
{
TArray<float> data(1);
data[2] = 2.0f;
}
}
}
When i try to compile(Im using Visual Studio 2017) it gives me an execption error at this position in Memory.h
static void* Copy(void *InDestination, const void *InSource, size_t InSize)
{
check_slow(InDestination);
check_slow(InSource);
check_slow(InSize > 0);
return memcpy(InDestination, InSource, InSize);
}
The test is getting called in the main function with this code:
int main()
{
Tests::TestAssertion();
Tests::TestMemory();
Tests::TestAllocator();
Tests::TestArrays();
return 0;
}
my goal currently is to look if the logger shows me the error here:
{
TArray<float> data(1);
data[2] = 2.0f;
}
here is a screenshot of the full error https://gyazo.com/6c1d6779623ffea97504f5b23f9fd7da
edit: here is the code for the allocator
#pragma once
#include <malloc.h>
#include "Core.h"
#define MEMORY_ALIGMENT 16
struct Memory
{
// TODO:Rework types.
static void* Allocate(const int32 InCount, const size_t InSize)
{
check_slow(InCount > 0);
check_slow(InSize > 0);
const size_t size = InSize * InCount;
return _aligned_malloc(size, MEMORY_ALIGMENT);
}
static void Free(void *InBlock)
{
check_slow(InBlock);
_aligned_free(InBlock);
}
static void* Copy(void *InDestination, const void *InSource, size_t InSize)
{
check_slow(InDestination);
check_slow(InSource);
check_slow(InSize > 0);
return memcpy(InDestination, InSource, InSize);
}
};
void* operator new (size_t InSize)
{
return Memory::Allocate(1, InSize);
}
void operator delete (void* InBlock)
{
Memory::Free(InBlock);
}
namespace Tests
{
struct MemoryTestStruct
{
uint32 p0;
uint32 p1;
uint32 p2;
uint32 p3;
};
FORCEINLINE void TestMemory()
{
MemoryTestStruct *t = new MemoryTestStruct();
check(t);
delete t;
}
}
edit2: Here is the code for the StackAlloctor
#pragma once
#include "../Core.h"
class DynamicLinearStackAllocator
{
private:
void *m_Data;
public:
template <typename T>
FORCEINLINE void Resize(const uint32 InElementCount, const uint32 InPreviousElementCount)
{
void *temp = Memory::Allocate(InElementCount, sizeof(T));
if (InPreviousElementCount > 0)
{
const SIZE_T size = sizeof(T) * InPreviousElementCount;
Memory::Copy(temp, m_Data, size);
Memory::Free(m_Data);
}
m_Data = temp;
}
template <typename T>
FORCEINLINE T* GetAllocator() const
{
return (T*)m_Data;
}
FORCEINLINE void Destroy()
{
Memory::Free(m_Data);
}
};
namespace Tests
{
FORCEINLINE void TestAllocator()
{
DynamicLinearStackAllocator alloc;
alloc.Resize<float>(2, 0);
alloc.Destroy();
}
}
You're not showing the code for your Allocator, but the problem is probably this line in your TArray constructor:
m_Allocator.Resize<T>(InElementCount, m_ElementCount);
At this point, m_ElementCount has not been initialized and will have some random value in it. Resize is then probably trying to free up memory that hasn't been allocated (because of the uninitialized value in m_ElementCount). You should pass in a 0 for the second parameter of the Resize call in your constructor
m_Allocator.Resize<T>(InElementCount, 0);
since there is no existing allocated memory to free.
Also, your default constructor for TArray should initialize m_Allocator.m_data to nullptr (or add a default constructor to DynamicLinearStackAllocator to do that) and set m_ElementCount to 0.

Windows Bitmap encoder only writing bottom few thousand pixels

The ReadBmpFromFile/Stream functions work fine. (Still a little slow but they otherwise work). The WriteBmpToFile/Stream functions work in that they successfully create a valid .bmp file but only the bottom few thousands of pixels, the rest of the file is black.
It shouldn't be that hard to see why, the pixel data is stored from bottom to top so the problem should be near the top of the file.
Reference: BMP File structure
Original:
Copy:
I stepped through with a debugger and the data is successfully being copied from the containing object. It shouldn't fail when I am reading from a file and then immediately writing it back:
if(_keyboard->KeyDown(KEY_S)) {
BitmapFileType bmp_test;
ReadBmpFromFile("maglot.bmp_test", bmp_test);
//Change filename to not destroy original!
WriteBmpToFile("maglot_copy.bmp_test", bmp_test);
//Allegro's implementation to test correct output against.
//save_bmp("maglot_copy.bmp", image->GetImage(), nullptr);
}
Bitmap class definition:
class BitmapFileType {
public:
struct Header {
std::vector<unsigned char> file_signature;
unsigned int file_size;
unsigned short unused1;
unsigned short unused2;
unsigned int pixel_array_offset;
unsigned int DIB_header_size;
unsigned int width;
unsigned int height;
unsigned short plane_count;
unsigned short bpp;
unsigned int compression_method;
unsigned int raw_size;
unsigned int print_resolution_horizontal;
unsigned int print_resolution_vertical;
unsigned int pallete_colors_count;
unsigned int important_colors_count;
Header() :
file_signature(2),
file_size(0),
unused1(0),
unused2(0),
pixel_array_offset(0),
DIB_header_size(0),
width(0),
height(0),
plane_count(0),
bpp(0),
compression_method(0),
raw_size(0),
print_resolution_horizontal(0),
print_resolution_vertical(0),
pallete_colors_count(0),
important_colors_count(0)
{ /* DO NOTHING */ }
Header(const Header& other) :
file_signature(other.file_signature),
file_size(other.file_size),
unused1(other.unused1),
unused2(other.unused2),
pixel_array_offset(other.pixel_array_offset),
DIB_header_size(other.DIB_header_size),
width(other.width),
height(other.height),
plane_count(other.plane_count),
bpp(other.bpp),
compression_method(other.compression_method),
raw_size(other.raw_size),
print_resolution_horizontal(other.print_resolution_horizontal),
print_resolution_vertical(other.print_resolution_vertical),
pallete_colors_count(other.pallete_colors_count),
important_colors_count(other.important_colors_count)
{ /* DO NOTHING */ }
Header& operator=(const Header& rhs) {
if(this == &rhs) return *this;
this->file_signature = rhs.file_signature;
this->file_size = rhs.file_size;
this->unused1 = rhs.unused1;
this->unused2 = rhs.unused2;
this->pixel_array_offset = rhs.pixel_array_offset;
this->DIB_header_size = rhs.DIB_header_size;
this->width = rhs.width;
this->height = rhs.height;
this->plane_count = rhs.plane_count;
this->bpp = rhs.bpp;
this->compression_method = rhs.compression_method;
this->raw_size = rhs.raw_size;
this->print_resolution_horizontal = rhs.print_resolution_horizontal;
this->print_resolution_vertical = rhs.print_resolution_vertical;
this->pallete_colors_count = rhs.pallete_colors_count;
this->important_colors_count = rhs.important_colors_count;
return *this;
}
};
struct PixelData {
std::vector<unsigned char> _pixel_data;
PixelData() : _pixel_data() { /* DO NOTHING */ }
PixelData(const PixelData& other) : _pixel_data(other._pixel_data) { /* DO NOTHING */ }
PixelData(const std::vector<unsigned char>& pixel_data) : _pixel_data(pixel_data) { /* DO NOTHING */ }
};
BitmapFileType() : _header(), _data() { /* DO NOTHING */ }
BitmapFileType(const BitmapFileType::Header& header) : _header(header), _data() { /* DO NOTHING */ }
BitmapFileType(const BitmapFileType::Header& header, const PixelData& data) : _header(header), _data(data) { /* DO NOTHING */ }
BitmapFileType& operator=(const BitmapFileType& rhs) {
if(this == &rhs) return *this;
_header = rhs._header;
_data = rhs._data;
return *this;
}
const Header& GetHeader() const {
return _header;
}
Header& GetHeader() {
return const_cast<Header&>(static_cast<const BitmapFileType&>(*this).GetHeader());
}
const PixelData& GetPixelData() const {
return _data;
}
PixelData& GetPixelData() {
return const_cast<PixelData&>(static_cast<const BitmapFileType&>(*this).GetPixelData());
}
protected:
private:
Header _header;
PixelData _data;
};
Function definitions:
#include "FileTypeUtility.h"
#include <fstream>
void WriteBmpToFile(const std::string& filename, const BitmapFileType& bmp) {
std::ofstream ofs;
ofs.open(filename);
WriteBmpToStream(ofs, bmp);
ofs.close();
}
void ReadBmpFromFile(const std::string& filename, BitmapFileType& bmp) {
std::ifstream ifs;
ifs.open(filename);
ReadBmpFromStream(ifs, bmp);
ifs.close();
}
void ReadBmpFromStream(std::istream& input_stream, BitmapFileType& bmp) {
if(input_stream.fail() || input_stream.bad() || input_stream.eof()) return;
std::vector<unsigned char> file_signature(2);
input_stream.read(reinterpret_cast<char*>(file_signature.data()), file_signature.size());
if((file_signature[0] != 'B' || file_signature[1] != 'M')) {
input_stream.seekg(-2, std::ios_base::cur);
input_stream.setstate(std::ios_base::failbit);
return;
}
unsigned int file_size = 0;
input_stream.read(reinterpret_cast<char*>(&file_size), sizeof(file_size));
unsigned short unused1 = 0;
input_stream.read(reinterpret_cast<char*>(&unused1), sizeof(unused1));
unsigned short unused2 = 0;
input_stream.read(reinterpret_cast<char*>(&unused2), sizeof(unused2));
unsigned int pixel_array_offset = 0;
input_stream.read(reinterpret_cast<char*>(&pixel_array_offset), sizeof(pixel_array_offset));
unsigned int DIB_header_size = 0;
input_stream.read(reinterpret_cast<char*>(&DIB_header_size), sizeof(DIB_header_size));
unsigned int width = 0;
input_stream.read(reinterpret_cast<char*>(&width), sizeof(width));
unsigned int height = 0;
input_stream.read(reinterpret_cast<char*>(&height), sizeof(height));
unsigned short plane_count = 0;
input_stream.read(reinterpret_cast<char*>(&plane_count), sizeof(plane_count));
unsigned short bpp = 0;
input_stream.read(reinterpret_cast<char*>(&bpp), sizeof(bpp));
unsigned int compression_method = 0;
input_stream.read(reinterpret_cast<char*>(&compression_method), sizeof(compression_method));
unsigned int raw_size = 0;
input_stream.read(reinterpret_cast<char*>(&raw_size), sizeof(raw_size));
unsigned int print_resolution_horizontal = 0;
input_stream.read(reinterpret_cast<char*>(&print_resolution_horizontal), sizeof(print_resolution_horizontal));
unsigned int print_resolution_vertical = 0;
input_stream.read(reinterpret_cast<char*>(&print_resolution_vertical), sizeof(print_resolution_vertical));
unsigned int pallete_colors_count = 0;
input_stream.read(reinterpret_cast<char*>(&pallete_colors_count), sizeof(pallete_colors_count));
unsigned int important_colors_count = 0;
input_stream.read(reinterpret_cast<char*>(&important_colors_count), sizeof(important_colors_count));
std::vector<unsigned char> pixel_array(raw_size);
input_stream.read(reinterpret_cast<char*>(pixel_array.data()), pixel_array.size());
BitmapFileType::PixelData bmpPixels(pixel_array);
BitmapFileType::Header bmpHeader;
bmpHeader.file_signature = file_signature;
bmpHeader.file_size = file_size;
bmpHeader.unused1 = unused1;
bmpHeader.unused2 = unused2;
bmpHeader.pixel_array_offset = pixel_array_offset;
bmpHeader.DIB_header_size = DIB_header_size;
bmpHeader.width = width;
bmpHeader.height = height;
bmpHeader.plane_count = plane_count;
bmpHeader.bpp = bpp;
bmpHeader.compression_method = compression_method;
bmpHeader.raw_size = raw_size;
bmpHeader.print_resolution_horizontal = print_resolution_horizontal;
bmpHeader.print_resolution_vertical = print_resolution_vertical;
bmpHeader.pallete_colors_count = pallete_colors_count;
bmpHeader.important_colors_count = important_colors_count;
bmp = BitmapFileType(bmpHeader, bmpPixels);
return;
}
void WriteBmpToStream(std::ostream& output_stream, const BitmapFileType& bmp) {
if(output_stream.fail() || output_stream.bad() || output_stream.eof()) return;
const BitmapFileType::Header& bmpHeader(bmp.GetHeader());
output_stream.write(reinterpret_cast<const char*>(bmpHeader.file_signature.data()), bmpHeader.file_signature.size());
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.file_size), sizeof(bmpHeader.file_size));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.unused1), sizeof(bmpHeader.unused1));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.unused2), sizeof(bmpHeader.unused2));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.pixel_array_offset), sizeof(bmpHeader.pixel_array_offset));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.DIB_header_size), sizeof(bmpHeader.DIB_header_size));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.width), sizeof(bmpHeader.width));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.height), sizeof(bmpHeader.height));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.plane_count), sizeof(bmpHeader.plane_count));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.bpp), sizeof(bmpHeader.bpp));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.compression_method), sizeof(bmpHeader.compression_method));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.raw_size), sizeof(bmpHeader.raw_size));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.print_resolution_horizontal), sizeof(bmpHeader.print_resolution_horizontal));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.print_resolution_vertical), sizeof(bmpHeader.print_resolution_vertical));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.pallete_colors_count), sizeof(bmpHeader.pallete_colors_count));
output_stream.write(reinterpret_cast<const char*>(&bmpHeader.important_colors_count), sizeof(bmpHeader.important_colors_count));
const BitmapFileType::PixelData& bmpPixelData(bmp.GetPixelData());
output_stream.write(reinterpret_cast<const char*>(bmpPixelData._pixel_data.data()), bmpPixelData._pixel_data.size());
return;
}