I am currently working on my final project for my Cpp class, which involves working with directX11 to create a 2D game. I have been following tutorials from the website rastertek.com (directX 11 series 2), and for the most part it has been going pretty smoothly. However the portion of code on shaders I finished up this morning had some errors right away.
At first it was giving me error C2719 in my colorshaderclass.cpp at lines 44 and 248 with my XMMATRIX values being passed in. After some quick research on the topic I changed those XMMATRIX values being passed in to constant references. I then went into my colorshaderclass.h file and changed the XMMATRIX values on lines 37 and 44 to constant references as necessary.
After doing that I no longer have error C2719 showing up. However now I am getting error C2678 (binary '=': no operator found which takes a left-hand operand of type 'const DirectX::XMMATRIX'), on lines 256, 257, and 258 of my colorshaderclass.cpp file. I've done a bit of research on this error too but it seems to be very situation dependent and I have had no luck with it.
Actually, I should say I think I understand why it is throwing the error (const on one side, a non-constant on the other), but I am stumped on what to do at this point as I had to make parts of the code into constant references to get them to work. I should also mention that I have less than six months of programming experience at this point, so sorry if this seems like an obvious fix or anything. If anybody has any insight or ideas it would be much appreciated.
Cheers!
There are also several other parts to the whole solution I can provide if needed, although none of them were throwing any errors.
The offending code is below (C2678)
worldMatrix = XMMatrixTranspose(worldMatrix);
viewMatrix = XMMatrixTranspose(viewMatrix);
projectionMatrix = XMMatrixTranspose(projectionMatrix);
and the XMMATRIX values I changed to constant references:
bool ColorShaderClass::SetShaderParameters(ID3D11DeviceContext* deviceContext, const XMMATRIX& worldMatrix, const XMMATRIX& viewMatrix, const XMMATRIX& projectionMatrix)
bool ColorShaderClass::Render(ID3D11DeviceContext* deviceContext, int indexCount, const XMMATRIX& worldMatrix, const XMMATRIX& viewMatrix, const XMMATRIX& projectionMatrix)
And what I changed in the header file
bool Render(ID3D11DeviceContext*Int, int, const XMMATRIX&, const XMMATRIX&, const XMMATRIX&);
bool SetShaderParameters(ID3D11DeviceContext*, const XMMATRIX&, const XMMATRIX&, const XMMATRIX&);
It's not clear from your report exactly what all the variable types are. Is your worldMatrix declared as XMFLOAT4X4? Both XMVECTOR and XMMATRIX have alignment requirements, so it is not recommended to use them directly as class/struct variables. If you are following that advice, then you need to use XMStoreFloat4x4 and XMLoadFloat4x4 to convert between XMFLOAT4X4 and XMMATRIX.
So a typical usage would be something like:
class MyClass
{
DirectX::XMFLOAT4X4 m_worldMatrix;
};
// ...
void MyClass::SomeFunction()
{
XMMATRIX worldMatrix = XMLoadFloat4x4( &m_worldMatrix );
// do some stuff with worldMatrix as an ``XMMATRIX``
XMStoreFloat4x4( &m_worldMatrix, worldMatrix );
}
Yes this is verbose, but intentionally. Most of the loss of performance when doing SIMD programming is converting to and from non-aligned and/or scalar types. This pattern encourages the advanced programmer to load the values into 'register proxy' types (XMMATRIX, XMVECTOR) and then do a lot of operations as such before storing them back into scalar or non-aligned types.
If you like the convenience of the C++ operator overloading, then take a look at SimpleMath in the DirectX Tool Kit. It provides some classes that 'wrap' DirectXMath so that it's more intuitive to use. It does have some performance implications, but unless you are really performance sensitive you won't notice. It is also very easy to intermix SimpleMath and DirectXMath types. The above example would be:
class MyClass
{
DirectX::SimpleMath::Matrix m_worldMatrix;
};
// ...
void MyClass::SomeFunction()
{
XMMATRIX worldMatrix = m_worldMatrix;
// do some stuff with worldMatrix as an ``XMMATRIX``
// or just use the methods and operator overloads directly
// of the ``Matrix`` SimpleMath type
m_worldMatrix = worldMatrix;
}
As for your parameter usage, you certainly can use const ref's like you are doing, but you might find it helpful to use the various DirectXMath calling-convention types described on MSDN. For your example, it would end up as:
bool XM_CALLCONV ColorShaderClass::SetShaderParameters(ID3D11DeviceContext* deviceContext, FXMMATRIX worldMatrix, CXMMATRIX viewMatrix, CXMMATRIX projectionMatrix)
This is not strictly necessary, but if you are trying to leverage the various SIMD-friendly calling conventions across x86 __fastcall, x86 __vectorcall, x64 __fastcall, x64 __vectorcall, and ARM these types and the XM_CALLCONV macro can achieve that.
Related
I would like to know if it's possible in C++ to change the type of a std::vector already filled with values, exactly as a union works, i.e.:
not changing any single bit of the binary content
not computing any type casting (no mathematical operations)
just reinterpreting the content of binary data using a new type (ex. uint16 or float32) without any memory copy or reallocation (as I would like to use vectors of several gigabytes in size)
For example, I have a vector filled with 20 values:
0x00, 0x01, 0x02, 0x03 ...
and I want to re-interpret it as a vector of 10 values, with the same overall binary content:
0x0001, 0x0203 (depending on the little endian / big endian convention)
The closest thing I could do is:
vector<uint8_t> test8(20);
uint16_t* pv16 = (uint16_t*) (&test8[0]);
vector<uint16_t> test16(pv16, pv16+10);
The result is exactly what I want, except that it makes a copy of the entire data, whereas I would like to use the existing data.
I would appreciate any help on this subject.
Thanks a lot for your answer.
You probably don't need a full-blown vector, just something that behaves like a container. You can create your own punned_view that just references the memory in the existing vector.
Please also read up on type punning and undefined behavior in C++, as it's quite a subtle topic. See https://blog.regehr.org/archives/959
#include <type_traits>
#include <cstring>
#include <cstdint>
#include <vector>
template <typename To>
class punned_view
{
static_assert(std::is_trivial<To>::value);
const char* begin_;
const char* end_;
public:
template <typename From>
punned_view(From* begin, From* end)
: begin_{reinterpret_cast<const char*>(begin)}
, end_{reinterpret_cast<const char*>(end)}
{
static_assert(sizeof(To) >= sizeof(From)); // exercise to make it work with smaller types too
static_assert(std::is_trivial<From>::value);
// add checks that size is a multiple of To here
}
std::size_t size() const noexcept
{
return (end_ - begin_) / sizeof(To);
}
class const_iterator
{
const char* current_;
public:
const_iterator(const char* current)
: current_{current}
{ }
const_iterator& operator++() noexcept
{
current_ += sizeof(To);
return *this;
}
To operator*() const noexcept
{
To result;
// only legal way to type pun in C++
std::memcpy(&result, current_, sizeof(result));
return result;
}
bool operator != (const_iterator other) const noexcept
{
return current_ != other.current_;
}
};
const_iterator begin() const noexcept { return {begin_}; }
const_iterator end() const noexcept { return {end_}; }
};
uint16_t sum_example(const std::vector<uint8_t>& vec)
{
punned_view<uint16_t> view{vec.data(), vec.data() + vec.size()};
uint16_t sum = 0;
for (uint16_t v : view)
sum += v;
return sum;
}
and thank you for all your quick and detailed answers. I was nicely surprised as the last time I used a forum (Eclipse) I remember getting exactly zero answers after an entire month...
Anyway, before I can try to test the different solutions you suggested, I wanted first to react to the excellent point rose by David Schwartz: yes my question is definitely a XY question, and yes I completely omitted to mention the context that led me to this exotic situation and what my real need ares.
So to make a long story short, what I really want is to read the content of a tiff image (satellite image with only gray-scale values, no RGB or any color combination) using gdal in C++, then perform some simple operations, some of them as basic as getting the right pixels values. Sounds simple as hell, doesn't it ? Now in real life everything is a nightmare when using gdal (which is as powerful as cryptic) and NOT knowing beforehand the actual pixel data type (which could be basically any kind of int or floating-point with any precision). As far as I could understand with tutorials, examples and forum, gdal offers me only 2 (hardly satisfactory) ways of reading the content of a tiff image:
1) either I know exactly the pixel datatype of my image (ex int16), and I have to hardcode it somewhere, which I cannot afford (and templates would not help here, as at a certain point I have to store the content of my image into a variable, which means I must know its precise type).
2) or I can read an image of any pixel data type but using a automatic conversion into a given target type (ex float64 to cover all possible value ranges). Sounds convenient and easy, but the downside is that this systematic conversion is a potentially huge waste of time and memory (think of uint8 in source array converted into float64 in target array!). An insane option for me as I usually work with massively big images (like several giga-pixels!)
3) I kind of figured out by myself a ugly/clumsy alternate solution, where I let gdal load the image content in a kind of "raw binary" content (officially an array of bytes) then eventually try to read it back by interpreting it according to the real datatype (that gdal can tell me afterwards). The good side is that the exact binary content of the image is loaded with no conversion whatsoever, so best speed and memory usage. The downside is that I end up eventually trying to fiddle with this binary data in order to interpret it correctly, avoiding any copy or mathematical operations.
So that's what led me into this awkward attempt of "in-place re-interpretation" of my data, or whatever the proper name is, just because I thought it would be a very simple and final step to getting the job done, but I might be wrong, and I might have overlooked simpler/cleaner solutions (actually I wish I have!).
Some final thoughts in order to "de-Y" my XY question !!!
_ using gdal library seems almost mandatory here, for as far as I know it is the only library that can handle properly the kind of image I am dealing with, i.e. multi-band tiff images (other libraries typically always consider 3 bands and interpret them blindly as RGB color components, which is absolutely not what I want here).
_ also I gave it a quick try with gdal for python but handling gigapixel large images in python sounds definitely like a wrong choice. Moreover my next step here should be to make a basic interactive image viewer (probably using Qt), so execution speed really matters.
_ I mentioned a lot using std::vector because I thought it would be easier to play with, but probably old-school C array would do the job.
_ finally I saw many answers mentioning alignment issue, that's really something I am not so comfortable with and that I wouldn't like to mess with...
So again, any further advice is welcome, including throwing away some of my previous attempts if it can simplify the situation and come out with a more direct solution, which is really something I would dream of.
Thanks again.
To get the data as another type, this could be achieved with some pointers and cast- magic.
From c++11 and later you can get a pointer to the raw data of a std::vector http://www.cplusplus.com/reference/vector/vector/data/
void* p;
uint16_t* p2;
std::vector<uint32_t> myvector;
myvector.push_back(0x12345678);
myvector.push_back(400);
p=myvector.data();
p2 = (uint16_t*)p;
for (size_t i = 0; i < 2*myvector.size(); i++) {
std::cout << *p2++ <<",";
}
As always when using casts of pointers you tell the compiler that you know better than it how to use and interpret the data and it will happily permit you to ignore alignment and endianess and do all harm you care with it.
I'm trying to use updated codes of "Frank Luna" book on directX11 where I using VS2017 with WindowsSDK10. I've read some notes about migration from Frank and did eveything he said in the link below :
http://www.d3dcoder.net/Data/Book4/d3d11Win10.htm
but got stuck here . I know there was same question from #poncho and answered well :
Access floats of XMMatrix - () operator not working
But I have trouble with type CXMMATRIX instead of XMMATRIX and I couldn't get result with the solution provided for him.
So I have to access the rows and columns of an CXMMATRIX :
void ExtractFrustumPlanes(XMFLOAT4 planes[6], CXMMATRIX M)
{
//
// Left
//
planes[0].x = M(0,3) + M(0,0);
planes[0].y = M(1,3) + M(1,0);
planes[0].z = M(2,3) + M(2,0);
planes[0].w = M(3,3) + M(3,0);
...
But I get :
call of an object of a class type without appropriate operator() or
conversion functions to pointer-to-function type
and
term does not evaluate to a function taking 2 arguments
It points to argument M of type CXMMATRIX where defined as below in DirectXMath.h :
// Fix-up for (2nd+) XMMATRIX parameters to pass by reference
typedef const XMMATRIX& CXMMATRIX;
What's all these errors about !?
Frank Luna's book is overall a great introduction to the Direct 11 API, but unfortunately suffers from heavily utilizing the legacy DirectX SDK which is deprecated per MSDN. One of those aspects is that he's actually using the xnamath library (a.k.a. xboxmath version 2) instead of the DirectXMath library (a.k.a. xboxmath version 3)
See Book Recommendations and Introducing DirectXMath
I made a number of changes when reworking the library as DirectXMath. First, the types are actually in C++ namespaces instead of the global namespace. In your headers, you should use full name specification:
#include <DirectXMath.h>
void MyFunction(..., DirectX::CXMMATRIX M);
In your cpp source files you should use:
#include <DirectXMath.h>
using namespace DirectX;
Another change was to strongly discourage the use of 'per-element' access on the XMVECTOR and XMMATRIX data types. As discussed in the DirectXMath Programmers Guide, these types are by design proxies for the SIMD register types which cannot be directly accessed by-element. Instead, you covert to the XMFLOAT4X4 representation which allows per-element access because that's a scalar structure.
You can see this by the fact that the operators you are trying to use are only defined for 'no-intrinsics' mode (i.e. when using scalar instead of SIMD operations like SSE, ARM-NEON, etc.):
#ifdef _XM_NO_INTRINSICS_
float operator() (size_t Row, size_t Column) const { return m[Row][Column]; }
float& operator() (size_t Row, size_t Column) { return m[Row][Column]; }
#endif
Again, by design, this process is a bit 'verbose' because it lets you know it's not free. Some people find this aspect of DirectXMath a little frustrating to use especially when they are first getting started. In that case, I recommend you take a look at the SimpleMath wrapper in the DirectX Tool Kit. You can use the types Vector3, Vector4, Matrix, etc. and they freely convert (through C++ operators and constructors) as needed to XMVECTOR and XMMATRIX. It's not nearly as efficient, but it's a lot more forgiving to use.
The particular function you wrote is also a bit problematic. First, it's a little odd to mix XMFLOAT4 and XMMATRIX parameters. For 'in-register, SIMD-friendly' calling convention, you'd use:
void XM_CALLCONV ExtractFrustumPlanes(XMVECTOR planes[6], FXMMATRIX M)
For details on why, see MSDN.
If you want to just entirely scalar math, use either the non-SIMD types:
void ExtractFrustumPlanes(XMFLOAT4 planes[6], const XMFLOAT4X4& M)
or better yet use SimpleMath so you can avoid having to write explicit conversions to/from XMVECTOR or XMMATRIX
using DirectX::SimpleMath;
void ExtractFrustumPlanes(Vector4 planes[6], const Matrix& M)
Note that the latest version of DirectXMath is on GitHub, NuGet, and vcpkg.
I'm trying to compile old Qt project and i encounter this error:
error: cannot convert 'float*' to 'qreal* {aka double*}' in
initialization
Here's the fragment of code:
void Camera::loadProjectionMatrix()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
qreal *dataMat = projectionMatrix_.data();
GLfloat matriceArray[16];
for (int i= 0; i < 16; ++i)
matriceArray[i] = dataMat[i];
glMultMatrixf(matriceArray);
}
What are my options to overcome this error?
The projection matrix will return float* to you as per documentation:
float * QMatrix4x4::data()
Returns a pointer to the raw data of this matrix.
The best practice would be to eliminate the qreal usage in your codebase regardless this case. When the contributors went through the Qt 5 refactoring, the qreal ancient concept was dropped as much as possible and definitely should not be used much in new code where the API deals with float.
The recommendation is to use float these days in such cases. This is a bit historical, really. Back then, it made sense to define qreal to double where available, but float where not, e.g. ARM platforms. See the old documentation:
typedef qreal
Typedef for double on all platforms except for those using CPUs with ARM architectures. On ARM-based platforms, qreal is a typedef for float for performance reasons.
In Qt 5, the documentation is slightly different, although the main concept seems to have remained the same:
typedef qreal
Typedef for double unless Qt is configured with the -qreal float option.
I would fix your code the following way:
void Camera::loadProjectionMatrix()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float *dataMat = projectionMatrix_.data();
GLfloat matriceArray[16];
for (int i= 0; i < 16; ++i)
matriceArray[i] = dataMat[i];
glMultMatrixf(matriceArray);
}
Strictly speaking, you could also go an alternative way to solve the issue, namely by using this method rather than data():
float & QMatrix4x4::operator()(int row, int column)
Returns a reference to the element at position (row, column) in this matrix so that the element can be assigned to.
In which case, you could even eliminate the dataMat variable and assign the items directly to your matriceArray in the iteration.
Going even further than that, you should consider using a Qt library for this common task, namely e.g. the opengl classes either in QtGui or Qt3D. It would make more sense to mess with low-level opengl API calls if you do something custom.
Apparently, projectionMatrix_.data() returns a float*, and you cannot assign a float* to a double* (which is what qreal* is in this case).
Use
float *dataMat = projectionMatrix_.data();
or
auto dataMat = projectionMatrix_.data();
instead. The latter sometimes has the advantage that it might still be correct code if the return type of the function changes for some reason, although that is nothing to expect from a mature library. Additionally, you cannot get the type wrong on accident.
I am reading through the 8th edition of the OpenGL Programming Guide by Shreiner Sellers Kessenich and Licea-Kane, and I keep seeing this "vmath" library being used for vector and matrices work.
I did a google search for vmath.h, but wasn't able to find anything. I did a search on stackoverflow and found one question where it has been used but nothing more.
My question is where or how can I install it or download it. I assumed it was something which came along with freeglut or whatever other opengl stuff I installed with "apt-get install", but apparently not since g++ can't find vmath.h.
Any ideas on how to get it installed?
#Blastfurnace provides the correct address to download. But I still have something to say.
Please use glm instead of vmath.h: http://glm.g-truc.net/0.9.5/index.html
I used vmath.h and found tons of bugs. Some definitions of operator causes recursive function call and stack overflows. Also the conversion between radius and degree is inverted.
line 11:
template <typename T>
inline T radians(T angleInRadians)
{
return angleInRadians * static_cast<T>(180.0/M_PI);
}
line 631:
static inline mat4 perspective(float fovy /* in degrees */, float aspect, float n, float f)
{
float top = n * tan(radians(0.5f*fovy)); // bottom = -top
float right = top * aspect; // left = -right
return frustum(-right, right, -top, top, n, f);
}
Obviously the tangent function accepts a radian input, but the function 'radian' converts the radian to degree instead.
line 137:
inline vecN& operator/=(const vecN& that)
{
assign(*this * that);
return *this;
}
It should be a division instead of a multiplication: assign(*this / that).
line 153:
inline vecN& operator/(const T& that)
{
assign(*this / that);
}
See? Recursive call of operator '/'. At least in Xcode this causes a stack overflow.
These bugs annoy me a lot, while glm library provides almost the same functions but much more stable code. I STRONGLY RECOMMEND you using glm instead of the current buggy vmath.h. Maybe when all these bugs are fixed, a simple vmath.h would be a better choice, while you need to give up at the moment.
The web site for the book can be found at The OpenGL Programming Guide. That page has a link to a .zip file with most of the code from the book. The vmath.h file is in the include directory.
In my OpenCL code (which is not coded by myself, it's just an example code from internet), there is the following sentence to use the function of clamp.
return clamp(color,0,1);
However it seems that this makes error during compilation, so I got the error info message by using CL_PROGRAM_BUILD_LOG from clGetProgramBuildInfo.
Error during compilation! (-11)
4483
build log
:211:9: error: call to 'clamp' is ambiguous
return clamp(color,0,1);
^~~~~
<built-in>:3558:26: note: candidate function
float4 __OVERLOADABLE__ clamp(float4 x, float min, float max) ;
^
<built-in>:3577:25: note: candidate function
float4 __OVERLOADABLE__ clamp(float4, float4, float4);
^
<built-in>:3556:26: note: candidate function
float3 __OVERLOADABLE__ clamp(float3 x, float min, float max) ;
^
<built-in>:3575:25: note: candidate function
float3 __OVERLOADABLE__ clamp(float3, float3, float3);
^
:296:52: error: address expression must be an lvalue or a function designator
r.origin = matrixVectorMultiply(viewTransform, &(float3)(0, 0, -1));
^~~~~~~~~~~~~~~~~~
:297:62: error: address expression must be an lvalue or a function designator
r.dir = normalize(matrixVectorMultiply(viewTransform, &(float3)(x, y, 0)) - r.origin);
^~~~~~~~~~~~~~~~~
Is there any necessary keyword for using clamp function in OpenCL code? BTW, I'm using the environment of the Linux Ubuntu 10.04 64bit.
Try the following
return clamp(color,0.0f,1.0f);
This way we know for sure that 2nd and 3rd params are not ambiguous and that you are trying to call the function:
clamp(float4 color, float min, float max);
If this doesn't work, then see your color param, but the 2nd and 3rd param should be fine now.
There are several overloaded clamp builtin functions in OpenCL; the compiler needs to select exactly one, based on the types of the arguments. Valid combinations are
T clamp(T,T,T) and T clamp(T,S,S)
where T is one of the OpenCL integral or floating point types, and S is the scalar type of an element of T when T is a vector type.
It would appear that your sample code was illegally mixing float and integer arguments to the call. The constants 1 and 0 are of type int, unlike 0.0f and 1.0f which are of type float.
See the quick reference card for more details.
I am getting the same problems on the same piece of code (http://www.gamedev.net/blog/1241/entry-2254210-realtime-raytracing-with-opencl-ii/). It is written poorly and managed to hang my pc.
The clamp() problem is indeed fixed by making sure that the last two arguments are floats.
The matrixVectorMultiply() problem is fixed by changing the signature of that function. It originally is:
float3 matrixVectorMultiply(__global float* matrix, float3* vector){
float3 result;
result.x = matrix[0]*((*vector).x)+matrix[4]*((*vector).y)+matrix[8]*((*vector).z)+matrix[12];
result.y = matrix[1]*((*vector).x)+matrix[5]*((*vector).y)+matrix[9]*((*vector).z)+matrix[13];
result.z = matrix[2]*((*vector).x)+matrix[6]*((*vector).y)+matrix[10]*((*vector).z)+matrix[14];
return result;
}
However there is absolutely no reason for vector to be a pointer, so you can remove the * before every occurrence of vector.
Then the code should compile, but the program probably still crashes.
Probably not your issue, but worth noting: Between OpenCL 1.0 and 1.1 clamp changed slightly, so if you are not careful you can have code that compiles in one version and not the other. Specifically, in the OpenCL 1.1 specification, "Appendix F – Changes", "F.1 Summary of changes from OpenCL 1.0" it says "The following features are added to the OpenCL C programming language (section 6):", then "New built-in functions", then "clamp integer function defined in section 6.11.3"
So you're best off fully qualifying your parameters.
Related to this, in OpenCL 1.1 added (vector, scalar) variant of integer functions min and max, so don't use those in 1.0 (cast the scalar parameters to vectors instead).