My yaw and pitch values aren't working when I try use trigonometry, even though the math is wrong when I run my aimbot application it should at least aim at different angles when I move but that is not the case. It's just stuck in one angle looking there. My yaw value when I run the application gets infinitesimally close to 0 so I think my calculations are going beyond the yaw value interval
Note that the intervals for the yaw value are [ 0, 360 ] and pitch is [ -90, 90 ]
#include "proc.h"
#include <iostream>
#include <thread>
#include <chrono>
#include <math.h>
#include <tgmath.h>
#define PI 3.14159265
//WORD m_XPos = 0x04;
//WORD m_YPos = 0x08;
//WORD m_ZPos = 0xC
//WORD YawVal = 0x0040;
//WORD PitchVal = 0x0044;
int main()
{
// Linking the game to my code essentially here
DWORD procID;
procID = getProcID(L"ac_client.exe");
HANDLE handle = 0;
handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
//base address for the player and base address for the enemy
uintptr_t localBaseAddress = 0x50F4F4;
uintptr_t entityBaseAddress = 0x50F4F8;
// setting up a link to get the values of playerx,y,z and view angles
std::vector<int> playerOffsets = { 0x4 };
uintptr_t playerX = findDMAAddress(handle, localBaseAddress, playerOffsets);
playerOffsets = { 0x8 };
uintptr_t playerY = findDMAAddress(handle, localBaseAddress, playerOffsets);
playerOffsets = { 0xC };
uintptr_t playerZ = findDMAAddress(handle, localBaseAddress, playerOffsets);
playerOffsets = { 0x40 };
uintptr_t playerYaw = findDMAAddress(handle, localBaseAddress, playerOffsets);
playerOffsets = { 0x44 };
uintptr_t playerPitch = findDMAAddress(handle, localBaseAddress, playerOffsets);
// setting up a link to get enemy x,y,z
/* note this is just one enemy which is the second enemy in the entity list
chain */
std::vector<int> enemyOffsets = { 0x8, 0x4 };
uintptr_t enemyX = findDMAAddress(handle, entityBaseAddress, enemyOffsets);
enemyOffsets = { 0x8, 0x8 };
uintptr_t enemyY = findDMAAddress(handle, entityBaseAddress, enemyOffsets);
enemyOffsets = { 0x8, 0xC };
uintptr_t enemyZ = findDMAAddress(handle, entityBaseAddress, enemyOffsets);
float myX = 0;
float myY = 0;
float myZ = 0;
float botX = 0;
float botY = 0;
float botZ = 0;
float placeholderX = 0;
float placeholderY = 0;
float placeholderZ = 0;
float magnitude = 0;
float tempYawValue = 0;
float tempPitchValue = 0;
float yawValue = 0;
float pitchValue = 0;
while (true)
{
// assign values to the floats i initialized previously for calculations
ReadProcessMemory(handle, (BYTE*)enemyX, &botX, sizeof(botX), 0);
ReadProcessMemory(handle, (BYTE*)enemyY, &botY, sizeof(botY), 0);
ReadProcessMemory(handle, (BYTE*)enemyZ, &botZ, sizeof(botZ), 0);
ReadProcessMemory(handle, (BYTE*)playerX, &myX, sizeof(myX), 0);
ReadProcessMemory(handle, (BYTE*)playerY, &myY, sizeof(myY), 0);
ReadProcessMemory(handle, (BYTE*)playerZ, &myZ, sizeof(myZ), 0);
ReadProcessMemory(handle, (BYTE*)playerYaw, &tempYawValue, sizeof(tempYawValue), 0);
ReadProcessMemory(handle, (BYTE*)playerPitch, &tempPitchValue, sizeof(tempPitchValue), 0);
//getting origin to get distance between me and enemy
placeholderX = botX - myX;
placeholderY = botY - myY;
placeholderZ = botZ - myZ;
magnitude = sqrt(pow(placeholderX, 2) + pow(placeholderY, 2) + pow(placeholderZ, 2));
//math for view angles
yawValue = (atan2(tempYawValue, tempPitchValue)) * (180 / PI);
pitchValue = acos(placeholderZ / magnitude) * (180 / PI);
// constantly writing to player view angles memory usign the angles i calculated
WriteProcessMemory(handle, (BYTE*)playerYaw, &yawValue, sizeof(yawValue), 0);
WriteProcessMemory(handle, (BYTE*)playerPitch, &pitchValue, sizeof(pitchValue), 0);
}
}
Related
I'm new to c++, and I need to use list container for my 3D marker-based watershed function. But I get strange bugs when I use list container. May I know what's wrong with my code?
Thank you so much!
I used a vector of list to save the wait-to-search pixel index.
I declare the variable in this way (GVInt32 is int32_t):
vector<list<GVInt32>> toSearchList;
And I used these two kinds of operations of list:
Add a new wait-to-search index at the end of a list
toSearchList[cnt].push_back(newidx);
Remove a searched element at the middle of a list(it is list<GVInt32>::iterator):
it = toSearchList[cnt].erase(it);
But I get two kinds of errors:
malloc(): memory corruption when I do
toSearchList[cnt].push_back(newidx);
I get not accessible elements in the end of the list when I inspect the variable in debugger:
[Not accessible elements][1]
https://i.stack.imgur.com/flJg3.png
The IDE is QT creator 4.15.2
The system is Ubuntu 18.04
The full code
watershed_wz.cpp:
#include "watershed_wz.h"
WaterShed_WZ::WaterShed_WZ()
{
}
array<GVInt32, 6> WaterShed_WZ::getNeighbor_WZ(const GVInt32 idx, const GVInt32 width, const GVInt32 height, const GVInt32 thick) {
GVInt32 SLICE = width * height;
GVInt32 z = idx / SLICE;
GVInt32 y = (idx%SLICE) / width;
GVInt32 x = idx % width;
array<GVInt32, 6> nIndex;
nIndex[0] = (x == 0) ? -1 : (idx - 1);
nIndex[1] = ((x + 1) == width) ? -1 : (idx + 1);
nIndex[2] = (y == 0) ? -1 : (idx - width);
nIndex[3] = ((y + 1) == height) ? -1 : (idx + width);
nIndex[4] = (z == 0) ? -1 : (idx - SLICE);
nIndex[5] = ((z + 1) == thick) ? -1 : (idx + SLICE);
return nIndex;
}
void WaterShed_WZ::Watershed3D_WZ(
const Mat im,
const GVInt32 width,
const GVInt32 height,
const GVInt32 thick,
GVInt32* label,
const vector<vector<GVInt32>> marker)
{
//<Parameter>
//<image> the image for watershed
//<width> the width of the image
//<height> the height of the image
//<thick> the thick of the image
//<label> the map to save result. need to allocate memory before use watershed
//<marker> the marker's index
// const GVByte* image=im.data;
auto t0 = chrono::high_resolution_clock::now();
QTextStream out(stdout);
// const GVInt32 SZ_slice = width * height;
// const GVInt32 SZ = SZ_slice * thick;
const GVInt32 markerNum = marker.size();
// create toSearchList. Saved pixel connected to labeled pixels and wait to search
vector<list<GVInt32>> toSearchList;
toSearchList.resize(markerNum);
// set label to INIT (unsearched)
// ::memset(label, -1, sizeof(GVInt32) * SZ);
// initialize
array<GVInt32, 6> nIdx;
for (size_t i = 0; i < markerNum; i++)
{
for (GVInt32 idx : marker[i])
{
// initialize label (which can be considered as a map of pointer to labelBar)
label[idx] = i + 1;
nIdx = getNeighbor_WZ(idx, width, height, thick);
for (GVInt32 newidx : nIdx)
{
if (newidx != -1)
{
if (label[newidx] == -1) {
toSearchList[i].push_back(newidx);
label[newidx] = -2;
}
}
}
}
}
//watershed
GVByte h;
GVInt32 idx;
for (int h_cnt = 0; h_cnt < (1+(int)GV_BYTE_MAX); h_cnt++) // water height
{
h = (GVByte)h_cnt;
for (GVInt32 cnt = 0; cnt < markerNum; cnt++) { // for each marker
list<GVInt32>::iterator it = toSearchList[cnt].begin();
while (!toSearchList[cnt].empty())
{
// for each pixel connected to the cnt-th labeled region
idx = *it;
// if this pixel is higher than water, ignore it
if (im.at<unsigned char>(idx) > h)
{
++it;
if(it == toSearchList[cnt].end())
{
break;
}
else
{
continue;
}
}
// this pixel is lower than water, assign it
label[idx] = cnt + 1;
// L.at<int>(idx)=cnt + 1;
// add new neighbor
nIdx = getNeighbor_WZ(idx, width, height, thick);
for (GVInt32 newidx : nIdx)
{
if (newidx != -1)
{
if (label[newidx]== -1) {
toSearchList[cnt].push_back(newidx);
label[newidx] = -2;
// L.at<int>(newidx)=-2;
}
}
}
// erase searched pixel
it = toSearchList[cnt].erase(it);
if(it == toSearchList[cnt].end())
{
break;
}
else
{
continue;
}
}
}
}
auto t1 = chrono::high_resolution_clock::now();
auto dt = 1.e-9 * chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count();
out << "Watershed used " << dt << " seconds.\n\n" << Qt::endl;
}
watershed_wz.h:
#ifndef WATERSHED_WZ_H
#define WATERSHED_WZ_H
#define _USE_MATH_DEFINES
#include <vector>
#include <array>
#include <list>
#include <opencv2/core.hpp> //basic building blocks of opencv
#include <opencv2/imgcodecs.hpp> // image io
#include <opencv2/highgui.hpp> //image display
#include <QDebug>
#include <QTextStream>
#include <chrono>
using namespace std;
using namespace cv;
typedef unsigned char GVByte;
typedef int32_t GVInt32;
//typedef uint32_t GVInt32U;
const GVByte GV_BYTE_MAX = UCHAR_MAX;
class WaterShed_WZ
{
public:
WaterShed_WZ();
static array<GVInt32, 6> getNeighbor_WZ(const GVInt32 idx, const GVInt32 width, const GVInt32 height, const GVInt32 thick);
static void Watershed3D_WZ(
const Mat im,
const GVInt32 width,
const GVInt32 height,
const GVInt32 thick,
GVInt32* label,
const vector<vector<GVInt32>> marker);
};
#endif // WATERSHED_WZ_H
try delete [cnt] index everywhere like this
toSearchList[cnt].end() --> toSearchList.end()
I am trying to play a sin wave sound with SDL2 by using the audio queue on C++. In order to do that, I have created a class "Speaker", which has a pushBeep function that is called every time a beep needs to be generated. I have created an AudioDevice successfully, and it is also successful when I do the QueueAudio to the device (I have checked on the debugger) but I can't seem to get any sound out of it.
I have tried changing the way I generate the samples in numerous ways, also, as I said previously, I have checked that the device is properly opened and the QueueAudio returns 0 for success.
This is the class
Speaker::Speaker()
{
SDL_AudioSpec ds;
ds.freq = Speaker::SPEAKER_FREQUENCY;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = NULL;
ds.userdata = this;
SDL_AudioSpec os;
this->dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, NULL);
std::cout << "DEVICE: " << this->dev << std::endl;
SDL_PauseAudioDevice(this->dev, 0);
}
Speaker::~Speaker()
{
SDL_CloseAudioDevice(this->dev);
}
void Speaker::pushBeep(double freq, int duration) {
int nSamples = duration * Speaker::SPEAKER_FREQUENCY / 1000;
float* samples = new float[nSamples];
double v = 0.0;
for (int idx = 0; idx < nSamples; idx++) {
//float value = (float)Speaker::SPEAKER_AMPLITUDE * std::sin(v * 2 * M_PI / Speaker::SPEAKER_FREQUENCY);
float value = 440.0;
samples[idx] = value;
v += freq;
}
int a = SDL_QueueAudio(this->dev, (void*)samples, nSamples * sizeof(float));
std::cout << a << std::endl;
delete[] samples;
samples = NULL;
}
And this is how I call it
Speaker s;
s.pushBeep(440.0, 1000);
When I try with the sin wave generation code (commented) it gives me a "double to float loss of precision" error. When I use the fixed value (not commented) it does not give the error, but it still does not work.
I expect the program to output the sound.
Couple of things you are missing, or maybe you didn't add to your code snippet. You didn't specify an audio callback so when you call SDL_QueueAudio(); it didn't know what to do with the data I'm pretty sure. And you weren't calling SDL_PauseAudioDevice() in your example with the delay.
#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <iostream>
namespace AudioGen
{
const int AMPLITUDE = 1;
const int SAMPLE_RATE = 44000;
// Globals
float *in_buffer;
SDL_atomic_t callback_sample_pos;
SDL_Event event;
SDL_bool running = SDL_TRUE;
/**
* Structure for holding audio metadata such as frequency
*/
struct AudioData
{
int sampleNum;
float frequency;
};
void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
AudioData &audio_data(*static_cast<AudioData*>(user_data));
int nSamples = bytes / 4; // For F32
std::cout << nSamples << std::endl;
for(int i = 0; i < nSamples; i++, audio_data.sampleNum++)
{
double time = (double)audio_data.sampleNum / (double)SAMPLE_RATE;
buffer[i] = (float)(AMPLITUDE * sin(2.0f * M_PI * audio_data.frequency * time));
}
}
int buffer_length;
void callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
int nSamples = bytes/4;
auto local_sample_pos = SDL_AtomicGet(&callback_sample_pos);
for(int i = 0; i < nSamples; ++i)
{
// Stop running audio if all samples are finished playing
if(buffer_length == local_sample_pos)
{
running = SDL_FALSE;
break;
}
buffer[i] = in_buffer[local_sample_pos];
++local_sample_pos;
}
SDL_AtomicSet(&callback_sample_pos, local_sample_pos);
}
class Speaker
{
public:
Speaker()
{
SDL_Init(SDL_INIT_AUDIO);
SDL_AudioSpec ds;
ds.freq = SAMPLE_RATE;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = callback;
ds.userdata = &ad; // metadata for frequency
SDL_AudioSpec os;
dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
}
~Speaker()
{
SDL_CloseAudioDevice(dev);
SDL_Quit();
}
void pushBeep(float frequency, int duration)
{
ad.frequency = frequency; // set the frequency for the beep
SDL_PauseAudioDevice(dev, 0);
SDL_Delay(duration); // wait while sound is playing
SDL_PauseAudioDevice(dev, 1);
}
void pushBeep2(float frequency, int duration )
{
int nSamples = duration * SAMPLE_RATE / 1000;
in_buffer = new float[nSamples];
buffer_length = nSamples;
for (int idx = 0; idx < nSamples; idx++) {
double time = (double)idx / (double)SAMPLE_RATE;
in_buffer[idx] = (float)(AMPLITUDE * std::sin(2.0f * M_PI * frequency * time));
}
SDL_QueueAudio(dev, in_buffer, nSamples * sizeof(float));
SDL_PauseAudioDevice(dev, 0);
while(running){
while(SDL_PollEvent(&event)!=0);
}
delete[] in_buffer;
}
private:
SDL_AudioDeviceID dev;
AudioData ad;
int sampleNum = 0;
};
} // End of namespace AudioGen
int main(int argc, char *argv[])
{
AudioGen::Speaker speaker;
//speaker.pushBeep(440, 1000);
speaker.pushBeep2(440.0f, 1000);
return 0;
}
The shader takes an SSBO of Photons that have a position, direction, wavelength and intensity and each thread is responsible for tracing exactly one photon through the grid, where at each grid cell the photon hits, the intensity is accumulated for each wavelength to create a spectral distribution for each grid cell.
The problem is that the shader works perfectly for 100,000 photons, but doesn't return a result for 1,000,000 photons.
I looked into the sizes for the SSBOs and all were within my GPUs (NVIDIA Quadro P6000) limits of 2GB:
SSBO Grid size: 1.5GB
SSBO Photons Size: 0.02GB
If I change the logic at some places it works with one million photons (see lines 87 and 114 for comments).
I currently can't see any explanation of why the shader fails for 1,000,000 photons, but works for 100,000 photons. The logic is the same and the buffer sizes are within limits. (That the buffer size can't be a problem is also confirmed by that it works when changing the logic.)
Below is the source code. If you want to try it yourself here is the code on github: https://github.com/TheJhonny007/TextureTracerDebug
Compute Shader:
#version 430
#extension GL_EXT_compute_shader: enable
#extension GL_EXT_shader_storage_buffer_object: enable
#extension GL_ARB_compute_variable_group_size: enable
const uint TEX_WIDTH = 1024u;
const uint TEX_HEIGHT = TEX_WIDTH;
const uint MIN_WAVELENGTH = 380u;
const uint MAX_WAVELENGTH = 740u;
const uint NUM_WAVELENGTHS = MAX_WAVELENGTH - MIN_WAVELENGTH;
// Size: 24 bytes -> ~40,000,000 photons per available gigabyte of ram
struct Photon {
vec2 position;// m
vec2 direction;// normalized
uint wavelength;// nm
float intensity;// 0..1 should start at 1
};
layout(std430, binding = 0) buffer Photons {
Photon photons[];
};
// Size: 1440 bytes -> ~700,000 pixels per available gigabyte of ram
struct Pixel {
uint intensityAtWavelengths[NUM_WAVELENGTHS];// [0..1000]
};
layout(std430, binding = 1) buffer Pixels {
//Pixel pixels[TEX_WIDTH][TEX_HEIGHT];
// NVIDIAs linker takes ages to link if the sizes are specified :(
Pixel[] pixels;
};
uniform float xAxisScalingFactor;
vec2 getHorizontalRectangleAt(int i) {
float x = pow(float(i), xAxisScalingFactor);
float w = pow(float(i + 1), xAxisScalingFactor);
return vec2(x, w);
}
uniform float rectangleHeight;
struct Rectangle {
float x;
float y;
float w;
float h;
};
layout (local_size_variable) in;
void addToPixel(uvec2 idx, uint wavelength, uint intensity) {
if (idx.x >= 0u && idx.x < TEX_WIDTH && idx.y >= 0u && idx.y < TEX_HEIGHT) {
uint index = (idx.y * TEX_WIDTH) + idx.x;
atomicAdd(pixels[index].intensityAtWavelengths[wavelength - MIN_WAVELENGTH], intensity);
}
}
/// Returns the rectangle at the given indices.
Rectangle getRectangleAt(ivec2 indices) {
vec2 horRect = getHorizontalRectangleAt(indices.x);
return Rectangle(horRect.x, rectangleHeight * float(indices.y), horRect.y, rectangleHeight);
}
uniform float shadowLength;
uniform float shadowHeight;
/// Returns the indices of the rectangle at the given location
ivec2 getRectangleIdxAt(vec2 location) {
int x = 0;
int y = int(location.y / rectangleHeight);
return ivec2(x, y);
}
float getRayIntersectAtX(Photon ray, float x) {
float slope = ray.direction.y / ray.direction.x;
return slope * (x - ray.position.x) + ray.position.y;
}
ivec2 getRayRectangleExitEdge(Photon ray, Rectangle rect) {
float intersectHeight = getRayIntersectAtX(ray, rect.x + rect.w);
// IF ONE OF THE FIRST TWO CONDITIONS GETS REMOVED IT WORKS WITH 1'000'000 PHOTONS OTHERWISE ONLY 100'000 WHY?
if (intersectHeight < rect.y) {
return ivec2(0, -1);
} else if (intersectHeight > rect.y + rect.h) {
return ivec2(0, 1);
} else {
return ivec2(1, 0);
}
}
void main() {
uint gid = gl_GlobalInvocationID.x;
if (gid >= photons.length()) return;
Photon photon = photons[gid];
ivec2 photonTexIndices = getRectangleIdxAt(photon.position);
while (photonTexIndices.x < TEX_WIDTH && photonTexIndices.y < TEX_HEIGHT &&
photonTexIndices.x >= 0 && photonTexIndices.y >= 0) {
// need to convert to uint for atomic add operations...
addToPixel(uvec2(photonTexIndices), photon.wavelength, uint(photon.intensity * 100.0));
ivec2 dir = getRayRectangleExitEdge(photon, getRectangleAt(photonTexIndices));
photonTexIndices += dir;
// When the ray goes out of bounds on the bottom then mirror it to simulate rays coming from
// the other side of the planet. This works because of the rotational symmetry of the system.
// IF COMMENTET OUT IT WORKS WITH 1'000'000 PHOTONS OTHERWISE ONLY 100'000 WHY?
if (photonTexIndices.y < 0) {
photonTexIndices.y = 0;
photon.position.y *= -1.0;
photon.direction.y *= -1.0;
}
}
}
Tracer.hpp
#ifndef TEXTURE_TRACER_HPP
#define TEXTURE_TRACER_HPP
#include <glm/glm.hpp>
#include <random>
namespace gpu {
// 6 * 4 = 24 Bytes
struct Photon {
glm::vec2 position; // m
glm::vec2 direction; // normalized
uint32_t waveLength; // nm
float intensity; // 0..1 should start at 1
};
class TextureTracer {
public:
TextureTracer();
uint32_t createShadowMap(size_t numPhotons);
private:
void initTextureTracer();
void traceThroughTexture(uint32_t ssboPhotons, size_t numPhotons);
Photon emitPhoton();
std::vector<Photon> generatePhotons(uint32_t count);
struct {
uint32_t uRectangleHeight;
uint32_t uShadowLength;
uint32_t uShadowHeight;
uint32_t uXAxisScalingFactor;
} mTextureTracerUniforms;
uint32_t mTextureTracerProgram;
std::mt19937_64 mRNG;
std::uniform_real_distribution<> mDistributionSun;
std::uniform_int_distribution<uint32_t> mDistributionWavelength;
std::bernoulli_distribution mDistributionBoolean;
};
} // namespace gpu
#endif // TEXTURE_TRACER_HPP
Tracer.cpp
#include "TextureTracer.hpp"
#include <GL/glew.h>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
#include <vector>
void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar *message, const void *userParam) {
if (type == GL_DEBUG_TYPE_ERROR)
fprintf(stderr, "GL ERROR: type = 0x%x, severity = 0x%x, message = %s\n",
type, severity, message);
else
fprintf(stdout, "GL INFO: type = 0x%x, severity = 0x%x, message = %s\n",
type, severity, message);
}
namespace gpu {
const double TEX_HEIGHT_TO_RADIUS_FACTOR = 4;
const double TEX_SHADOW_LENGTH_FACTOR = 8;
const uint32_t TEX_WIDTH = 1024u;
const uint32_t TEX_HEIGHT = TEX_WIDTH;
const double RADIUS = 6'371'000.0;
const double RADIUS_FACTORED = RADIUS * TEX_HEIGHT_TO_RADIUS_FACTOR;
const double SUN_RADIUS = 695'510'000.0;
const double DIST_TO_SUN = 149'600'000'000.0;
const double ATMO_HEIGHT = 42'000.0;
std::string loadShader(const std::string &fileName) {
std::ifstream shaderFileStream(fileName, std::ios::in);
if (!shaderFileStream.is_open()) {
std::cerr << "Could not load the GLSL shader from '" << fileName << "'!"
<< std::endl;
exit(-1);
}
std::string shaderCode;
while (!shaderFileStream.eof()) {
std::string line;
std::getline(shaderFileStream, line);
shaderCode.append(line + "\n");
}
return shaderCode;
}
void TextureTracer::initTextureTracer() {
mTextureTracerProgram = glCreateProgram();
uint32_t rayTracingComputeShader = glCreateShader(GL_COMPUTE_SHADER);
std::string code = loadShader("../resources/TextureTracer.glsl");
const char *shader = code.c_str();
glShaderSource(rayTracingComputeShader, 1, &shader, nullptr);
glCompileShader(rayTracingComputeShader);
glAttachShader(mTextureTracerProgram, rayTracingComputeShader);
glLinkProgram(mTextureTracerProgram);
mTextureTracerUniforms.uRectangleHeight =
glGetUniformLocation(mTextureTracerProgram, "rectangleHeight");
mTextureTracerUniforms.uShadowHeight =
glGetUniformLocation(mTextureTracerProgram, "shadowHeight");
mTextureTracerUniforms.uShadowLength =
glGetUniformLocation(mTextureTracerProgram, "shadowLength");
mTextureTracerUniforms.uXAxisScalingFactor =
glGetUniformLocation(mTextureTracerProgram, "xAxisScalingFactor");
glDetachShader(mTextureTracerProgram, rayTracingComputeShader);
glDeleteShader(rayTracingComputeShader);
}
TextureTracer::TextureTracer()
: mRNG(1L), mDistributionSun(
std::uniform_real_distribution<>(-SUN_RADIUS, SUN_RADIUS)),
mDistributionWavelength(
std::uniform_int_distribution<uint32_t>(380, 739)),
mDistributionBoolean(std::bernoulli_distribution(0.5)) {
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(MessageCallback, nullptr);
initTextureTracer();
}
double raySphereDistance(glm::dvec2 origin, glm::dvec2 direction,
glm::dvec2 center, double radius) {
glm::dvec2 m = origin - center;
double b = glm::dot(m, direction);
double c = glm::dot(m, m) - (radius * radius);
if (c > 0.0 && b > 0.0)
return -1.0;
double discr = b * b - c;
// A negative discriminant corresponds to ray missing sphere
if (discr < 0.0)
return -1.0;
// Ray now found to intersect sphere, compute smallest t value of intersection
return glm::max(0.0, -b - glm::sqrt(discr));
}
Photon TextureTracer::emitPhoton() {
std::uniform_real_distribution<> distributionEarth(0.0, ATMO_HEIGHT);
glm::dvec2 target = {0.0, RADIUS + distributionEarth(mRNG)};
double d;
do {
d = glm::length(glm::dvec2(mDistributionSun(mRNG), mDistributionSun(mRNG)));
} while (d > SUN_RADIUS);
glm::dvec2 startPosition =
glm::dvec2(-DIST_TO_SUN, mDistributionBoolean(mRNG) ? d : -d);
glm::dvec2 direction = glm::normalize(target - startPosition);
startPosition +=
direction * raySphereDistance(startPosition, direction, {0.0, 0.0},
RADIUS + ATMO_HEIGHT);
return {glm::vec2(0.0, startPosition.y), glm::vec2(direction),
mDistributionWavelength(mRNG), 1.0f};
}
std::vector<Photon> TextureTracer::generatePhotons(uint32_t count) {
std::vector<Photon> photons(count);
std::generate(photons.begin(), photons.end(),
[this]() { return emitPhoton(); });
return photons;
}
void TextureTracer::traceThroughTexture(uint32_t ssboPhotons,
size_t numPhotons) {
glUseProgram(mTextureTracerProgram);
glUniform1f(mTextureTracerUniforms.uRectangleHeight,
RADIUS_FACTORED / TEX_HEIGHT);
const double shadowLength =
TEX_SHADOW_LENGTH_FACTOR * (DIST_TO_SUN * RADIUS) / (SUN_RADIUS - RADIUS);
glUniform1f(mTextureTracerUniforms.uShadowLength, shadowLength);
glUniform1f(mTextureTracerUniforms.uShadowHeight, RADIUS_FACTORED);
const double xAxisScalingFactor =
glm::log(shadowLength) / glm::log(static_cast<double>(TEX_WIDTH));
glUniform1f(mTextureTracerUniforms.uXAxisScalingFactor,
static_cast<float>(xAxisScalingFactor));
const uint32_t MIN_WAVELENGTH = 380u;
const uint32_t MAX_WAVELENGTH = 740u;
const uint32_t NUM_WAVELENGTHS = MAX_WAVELENGTH - MIN_WAVELENGTH;
size_t pixelBufferSize =
TEX_WIDTH * TEX_HEIGHT * NUM_WAVELENGTHS * sizeof(uint32_t);
uint32_t ssboPixels;
glGenBuffers(1, &ssboPixels);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboPixels);
glBufferData(GL_SHADER_STORAGE_BUFFER, pixelBufferSize, nullptr,
GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssboPhotons);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssboPixels);
const uint32_t numThreads = 32u;
const uint32_t numBlocks = numPhotons / numThreads;
std::cout << "numBlocks: " << numBlocks << std::endl;
glDispatchComputeGroupSizeARB(numBlocks, 1, 1, numThreads, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
struct Pixel {
uint32_t intensityAtWavelengths[NUM_WAVELENGTHS];
};
std::vector<Pixel> pixels(TEX_WIDTH * TEX_HEIGHT);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboPixels);
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, pixelBufferSize,
pixels.data());
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
for (int y = 0; y < TEX_HEIGHT; ++y) {
printf("%4i | ", y);
for (int x = 0; x < TEX_WIDTH; ++x) {
Pixel p = pixels[y * TEX_WIDTH + x];
int counter = 0;
for (uint32_t i : p.intensityAtWavelengths) {
counter += i;
}
if (counter == 0) {
printf(" ");
} else if (counter > 100'000'000) {
printf("%4s", "\u25A0");
} else if (counter > 10'000'000) {
printf("%4s", "\u25A3");
} else if (counter > 1'000'000) {
printf("%4s", "\u25A6");
} else if (counter > 100'000) {
printf("%4s", "\u25A4");
} else {
printf("%4s", "\u25A1");
}
}
std::cout << std::endl;
}
glDeleteBuffers(1, &ssboPixels);
glUseProgram(0);
}
uint32_t TextureTracer::createShadowMap(size_t numPhotons) {
std::vector<Photon> photons = generatePhotons(numPhotons);
uint32_t ssboPhotons;
glGenBuffers(1, &ssboPhotons);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboPhotons);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(Photon) * photons.size(),
photons.data(), GL_DYNAMIC_COPY);
traceThroughTexture(ssboPhotons, photons.size());
glDeleteBuffers(1, &ssboPhotons);
glDeleteProgram(mTextureTracerProgram);
glDisable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(nullptr, nullptr);
return 0;
}
}
main.cpp
#include <GL/glew.h>
#include <GL/glut.h>
#include "TextureTracer.hpp"
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutCreateWindow("OpenGL needs a window o.O");
glewInit();
auto mapper = gpu::TextureTracer();
// WITH 100'000 PHOTONS IT WORKS, WITH 1'000'000 PHOTONS NOT WHY?
mapper.createShadowMap(100'000);
return 0;
}
Operating systems cancel GPU program executions if they take too long. On Windows it is generally two seconds and on Linux it is five seconds most of the time, but it can vary.
This is to detect GPU programs that are stuck and cancel them. There are different methods to get around this timeout, but they all require admin/root privileges, which is not always available.
If possible the execution can be split up into multiple invocations like in the following snippet:
const uint32_t passSize = 2048u;
const uint32_t numPasses = (numPhotons / passSize) + 1;
const uint32_t numThreads = 64u;
const uint32_t numBlocks = passSize / numThreads;
glUniform1ui(glGetUniformLocation(mTextureTracerProgram, "passSize"), passSize);
for (uint32_t pass = 0u; pass < numPasses; ++pass) {
glUniform1ui(glGetUniformLocation(mTextureTracerProgram, "pass"), pass);
glDispatchComputeGroupSizeARB(numBlocks, 1, 1, numThreads, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glFlush();
glFinish();
}
The glFlush() and glFinish() calls are important or the executions will get bundled together and the OS triggers a timeout anyways.
In the shader you just need to access the right sections of the input data like so:
// other stuff
uniform uint pass;
uniform uint passSize;
void main() {
uint gid = gl_GlobalInvocationID.x;
uint passId = pass * passSize + gid;
if (passId >= photons.length()) return;
Photon photon = photons[passId];
// rest of program
}
This is all.
If you want to disable the OS timeouts here is a relevant post for Linux: https://stackoverflow.com/a/30520538/5543884
And here is a post regarding Windows: https://stackoverflow.com/a/29759823/5543884
I'm using HMC5883L sensor to measure magnetic field but when I look to the data on my ESP8266 it misses the decimals... The value should be, for example, "-234.54" and I got only "-234.00". I'm trying to fix this looking into the library but it didn't work.
My structures in HMC5883L.h:
struct MagnetometerScaled
{
float XAxis;
float YAxis;
float ZAxis;
};
struct MagnetometerRaw
{
float XAxis;
float YAxis;
float ZAxis;
};
Parts of HMC5883L.cpp in use:
MagnetometerRaw HMC5883L::ReadRawAxis()
{
const int8_t* buffer = Read(DataRegisterBegin, 6);
MagnetometerRaw raw = MagnetometerRaw();
raw.XAxis = (buffer[0] << 8) | buffer[1];
raw.ZAxis = (buffer[2] << 8) | buffer[3];
raw.YAxis = (buffer[4] << 8) | buffer[5];
delete [] buffer;
return raw;
}
MagnetometerScaled HMC5883L::ReadScaledAxis()
{
MagnetometerRaw raw = ReadRawAxis();
MagnetometerScaled scaled = MagnetometerScaled();
scaled.XAxis = raw.XAxis * m_Scale; // m_scale = 0.92 -> A float value
scaled.ZAxis = raw.ZAxis * m_Scale; // m_scale = 0.92 -> A float value
scaled.YAxis = raw.YAxis * m_Scale; // m_scale = 0.92 -> A float value
return scaled;
}
int8_t* HMC5883L::Read(int address, int length)
{
Wire.beginTransmission(HMC5883L_Address);
Wire.write(address);
Wire.endTransmission();
Wire.beginTransmission(HMC5883L_Address);
Wire.requestFrom(HMC5883L_Address, length);
// uint8_t buffer[length];
int8_t *buffer = new int8_t[length];
if(Wire.available() == length)
{
for(uint8_t i = 0; i < length; i++)
{
buffer[i] = Wire.read();
}
}
Wire.endTransmission();
return buffer;
}
In run this code (basically) using:
HMC5883L magnetometer;
MagnetometerScaled scaledVals;
scaledVals = magnetometer.ReadScaledAxis();
Serial.println(scaledVals.XAxis);
If I left some important part of the code behind, just ask for it :)
EDIT1: If I run Serial.println(1.01); it prints the value correctly (output = 1.01). So, Serial.println() is not truncating float values...
EDIT2: As I see, the problem seems to be with the type returned by Read() function. Maybe if I change it to char* instead of int8_t I'll be able to receive the decimals on the right way. My question related to this is with the ReadRawAxis() function. How to get the data from buffer?
I am trying to compile a project using make command.
I have several occured errors about namespace std::.
I am using Ubuntu and I think I've installed all I need to compile C++ language.
Here's the code:
#include "texture.hpp"
#include "texturefetch.hpp"
#include <png.h>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <assert.h>
#include <string>
Texture::~Texture(){
delete[] mPixels;
for (int i=1; i<mlodmax+1; ++i)
delete[] mMipMapLevels[i];
delete[] mMipMapLevels;
}
bool Texture::getclamp() const
{
return clamp;
}
void Texture::setclamp(bool value)
{
clamp = value;
}
int Texture::load(std::string filename){
FILE *fp;
png_byte magic[8];
/* open image file */
fp = std::fopen (filename.c_str(), "rb");
if (!fp) {
fprintf (stderr, "error: couldn't open \"%s\"!\n", filename.c_str());
return 0;
}
/* read magic number */
fread (magic, 1, sizeof (magic), fp);
/* check for valid magic number */
if (!png_check_sig (magic, sizeof (magic))) {
fprintf (stderr, "error: \"%s\" is not a valid PNG image!\n", filename.c_str());
fclose (fp);
return 0;
}
/* create a png read struct */
png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
fclose (fp);
return 0;
}
/* create a png info struct */
png_infop info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr) {
fclose (fp);
png_destroy_read_struct (&png_ptr, NULL, NULL);
return 0;
}
/* initialize the setjmp for returning properly after a libpng
error occured */
if (setjmp (png_jmpbuf (png_ptr))) {
fclose (fp);
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
return 0;
}
/* setup libpng for using standard C fread() function
with our FILE pointer */
png_init_io (png_ptr, fp);
/* tell libpng that we have already read the magic number */
png_set_sig_bytes (png_ptr, sizeof (magic));
/* read png info */
png_read_info (png_ptr, info_ptr);
int bit_depth, color_type;
/* get some usefull information from header */
bit_depth = png_get_bit_depth (png_ptr, info_ptr);
color_type = png_get_color_type (png_ptr, info_ptr);
/* convert index color images to RGB images */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb (png_ptr);
/* convert 1-2-4 bits grayscale images to 8 bits
grayscale. */
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha (png_ptr);
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
else if (bit_depth < 8)
png_set_packing (png_ptr);
/* update info structure to apply transformations */
png_read_update_info (png_ptr, info_ptr);
/* retrieve updated information */
png_get_IHDR (png_ptr, info_ptr,
(png_uint_32*)(&mWidth),
(png_uint_32*)(&mHeight),
&bit_depth, &color_type,
NULL, NULL, NULL);
switch (color_type) {
case PNG_COLOR_TYPE_GRAY:
mPixelFormat = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
mPixelFormat = 2;
break;
case PNG_COLOR_TYPE_RGB:
mPixelFormat = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
mPixelFormat = 4;
break;
default:
/* Badness */
break;
}
/* we can now allocate memory for storing pixel data */
mPixels = new unsigned char[mWidth * mHeight * mPixelFormat];
png_bytep *row_pointers;
/* setup a pointer array. Each one points at the begening of a row. */
row_pointers = new png_bytep[mHeight];
for (int i = 0; i < mHeight; ++i) {
row_pointers[i] = (png_bytep)(mPixels +
((mHeight - (i + 1)) * mWidth * mPixelFormat));
}
/* read pixel data using row pointers */
png_read_image (png_ptr, row_pointers);
/* finish decompression and release memory */
png_read_end (png_ptr, NULL);
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
fclose (fp);
/* we don't need row pointers anymore */
delete[] row_pointers;
return 1;
}
Texture::Texture(std::string filename) : mPixels(NULL), mMipMapLevels(NULL), hasmipmap(false), mSu(1.f), mSv(1.f), clamp(false){
if (!load(filename)) {
std::cerr << "Erreur : impossible de lire le fichier " << filename << std::endl;
} else {
mlodmax = (int)std::floor(std::min(std::log2(mWidth), std::log2(mHeight)));
}
}
bool Texture::prefilter(){
hasmipmap = buildmipmaps();
return hasmipmap;
}
bool Texture::buildmipmaps(){
mMipMapLevels = new unsigned char*[mlodmax+1];
mMipMapLevels[0] = mPixels;
for (int i=1;i<mlodmax+1; ++i)
mMipMapLevels[i]=NULL;
// Call of the student function
return prefilterTexture(mMipMapLevels, mWidth, mHeight, mPixelFormat, mlodmax+1);
}
void Texture::setScale(float su, float sv){
mSu = 1.f/su;
mSv = 1.f/sv;
}
void Texture::getPixel(float u, float v, float lod, Color &color){
if (clamp){
u = (u>0) ? ((u<1) ? u : 1) : 0;
v = (v>0) ? ((v<1) ? v : 1) : 0;
}
u = mSu*u;
v = mSv*v;
float scaledU = u * (mWidth - 1);
float scaledV = v * (mHeight - 1);
// color = Color(u,v,0);
// return;
int s = ((int)scaledU) % mWidth;
int t = ((int)scaledV) % mHeight;
float ds = scaledU - std::floor(scaledU);
float dt = scaledV - std::floor(scaledV);
if (s<0){
s = s+mWidth;
}
if (t<0){
t = t+mHeight;
}
// Nearest
// color = interpolate(mPixels, mWidth, mHeight, s,t, 0.f,0.f);
// return;
// Linear
// color = interpolate(mPixels, mWidth, mHeight, s,t, ds, dt);
// return;
/* Filtrage */
lod = std::min(lod-1, (float)mlodmax);
if (lod > 0) {
// color = Color(0, std::floor(lod), 0);
// return;
int baselod = (int)std::floor(lod);
int pix = (int)(std::pow(2.f,baselod)); // bigger inferior mipmap level
if (hasmipmap){
// Sous-echantillonnage --> filtrage mip-map
Color color1 = integrateMipMap(baselod, ((float)s + ds)/pix, ((float)t + dt)/pix, mWidth/pix, mHeight/pix);
if (baselod < mlodmax){
pix = std::pow(2.f,baselod+1); // smaller superior mipmap level
Color color2 = integrateMipMap(baselod+1, ((float)s + ds)/pix, ((float)t + dt)/pix, mWidth/pix, mHeight/pix);
float dm = lod - std::floor(lod);
color = color1 * (1-dm) + color2 * dm;
} else {
color = color1;
}
} else {
int cs = pix * (s/pix);
int ct = pix * (t/pix);
Color color1 = integrateExplicit(mMipMapLevels[0], mWidth, mHeight, mPixelFormat, cs, ct, pix, pix);
if (baselod < mlodmax){
pix = std::pow(2.f,baselod+1); // smaller superior mipmap level
cs = pix * (s/pix);
ct = pix * (t/pix);
Color color2 = integrateExplicit(mMipMapLevels[0], mWidth, mHeight, mPixelFormat, cs, ct, pix, pix);
float dm = lod - std::floor(lod);
color = color1 * (1-dm) + color2 * dm;
} else {
color = color1;
}
}
} else {
// color = Color(1/*fabsf(lod)*/, 0, 0);
// return;
color = interpolate(mPixels, mWidth, mHeight, s,t, ds,dt);
}
}
Color Texture::integrateMipMap(int level, float s, float t, int w, int h){
Color color(0.f, 0.f, 0.f);
color = interpolate(mMipMapLevels[level], w, h, (int)s, (int)t, s-std::floor(s), t-std::floor(t));
return color;
}
Color Texture::integrateExplicit(unsigned char *pixels, int imageWidth, int imageHeight, int pixelFormat, float s, float t, int w, int h){
#if 0
Color color(0.f, 0.f, 0.f);
for (int i=0; i<h; i++)
for (int j=0; j<w; j++) {
int k = ((int)(t+i)) % imageHeight;
int l = ((int)(s+j)) % imageWidth;
int linPos = (k*imageWidth + l)*(pixelFormat);
Color centerColor(((float) pixels[linPos])/255.0, ((float) pixels[linPos+1])/255.0, ((float) pixels[linPos+2])/255.0);
color = color + centerColor;
}
color = color * (1.f/(w*h));
return color;
#endif
// Call of the student function
return integrateTexture(pixels, imageWidth, imageHeight, pixelFormat, s, t, w, h);
}
Color Texture::interpolate(unsigned char *pixels, int w, int h, int s, int t, float ds, float dt){
#if 0
Color color;
// Sur échantillonnage --> interpolation
// nearest texel
int linPos = (t*w + s)*(mPixelFormat);
Color centerColor(((float) pixels[linPos])/255.0, ((float) pixels[linPos+1])/255.0, ((float) pixels[linPos+2])/255.0);
Color rightColor;
int r = std::min(s+1, w-1);
int posds = (t*w + r)*(mPixelFormat);
rightColor = Color(
((float) pixels[posds])/255.0,
((float) pixels[posds+1])/255.0,
((float) pixels[posds+2])/255.0
);
Color upColor;
int p = std::min(t+1, h-1);
int posdt = (p*w + s)*(mPixelFormat);
upColor = Color (
((float) pixels[posdt])/255.0,
((float) pixels[posdt+1])/255.0,
((float) pixels[posdt+2])/255.0
);
Color upRightColor;
int posdtds = (p*w + r)*(mPixelFormat);
upRightColor = Color (
((float) pixels[posdtds])/255.0,
((float) pixels[posdtds+1])/255.0,
((float) pixels[posdtds+2])/255.0
);
rightColor = centerColor*(1-ds) + rightColor*ds;
upColor = upColor*(1-ds) + upRightColor*ds;
color = rightColor*(1-dt) + upColor*dt;
return color;
#endif
// Call of the student function
return interpolateTexture(pixels, w, h, mPixelFormat, (float)s+ds, (float)t+dt);
}
And here's errors in terminal:
In file included from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:1:0:
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.hpp: In member function ‘float Texture::computeMipmapLevel(const Vector3D&, const Vector3D&)’:
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.hpp:55:16: error: ‘log2’ is not a member of ‘std’
return std::log2(std::max(dTdx.norm()*width()*mSu, dTdy.norm()*height()*mSv));
^
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.hpp:55:16: note: suggested alternative:
In file included from /usr/include/features.h:374:0,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/os_defines.h:39,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++config.h:426,
from /usr/include/c++/4.8/cmath:41,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/vector3d.hpp:3,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.hpp:4,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:1:
/usr/include/x86_64-linux-gnu/bits/math-finite.h:344:15: note: ‘log2’
extern double __REDIRECT_NTH (log2, (double), __log2_finite);
^
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp: In constructor ‘Texture::Texture(std::string)’:
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:162:44: error: ‘log2’ is not a member of ‘std’
mlodmax = (int)std::floor(std::min(std::log2(mWidth), std::log2(mHeight)));
^
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:162:44: note: suggested alternative:
In file included from /usr/include/features.h:374:0,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/os_defines.h:39,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++config.h:426,
from /usr/include/c++/4.8/cmath:41,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/vector3d.hpp:3,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.hpp:4,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:1:
/usr/include/x86_64-linux-gnu/bits/math-finite.h:344:15: note: ‘log2’
extern double __REDIRECT_NTH (log2, (double), __log2_finite);
^
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:162:63: error: ‘log2’ is not a member of ‘std’
mlodmax = (int)std::floor(std::min(std::log2(mWidth), std::log2(mHeight)));
^
/home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:162:63: note: suggested alternative:
In file included from /usr/include/features.h:374:0,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/os_defines.h:39,
from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++config.h:426,
from /usr/include/c++/4.8/cmath:41,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/vector3d.hpp:3,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.hpp:4,
from /home/celine/OIM-LancerDeRayons-2014/coreraytracer/texture.cpp:1:
/usr/include/x86_64-linux-gnu/bits/math-finite.h:344:15: note: ‘log2’
extern double __REDIRECT_NTH (log2, (double), __log2_finite);
I took a look on internet and I tried to include and but it's still not working...
Thanks!
log2 is a C99 function. It's not in C++98, and therefore not in the std namespace. Either compile in C++11 mode (C++11 is aligned with C99):
// g++ -std=c++11
#include <cmath>
#include <iostream>
int main()
{
std::cout << std::log2(3) << std::endl;
}
... or get the function from the C header, without the namespace:
// g++ -std=c++98
#include <iostream>
#include <math.h>
int main()
{
std::cout << log2(3) << std::endl;
}