Add renderer stuff

This commit is contained in:
2025-03-06 13:49:52 +03:00
parent d9437c8619
commit dd05797b95
11 changed files with 730 additions and 6 deletions

View File

@@ -137,10 +137,22 @@ SOURCE=.\render\renderdevice.cpp
# End Source File
# Begin Source File
SOURCE=.\render\rendertarget.cpp
# End Source File
# Begin Source File
SOURCE=.\filesystem\stream.cpp
# End Source File
# Begin Source File
SOURCE=.\render\texture2d.cpp
# End Source File
# Begin Source File
SOURCE=.\render\texturesmanager.cpp
# End Source File
# Begin Source File
SOURCE=.\render\vertexbuffer.cpp
# End Source File
# End Group
@@ -193,10 +205,22 @@ SOURCE=.\render\renderdevice.h
# End Source File
# Begin Source File
SOURCE=.\render\rendertarget.h
# End Source File
# Begin Source File
SOURCE=.\filesystem\stream.h
# End Source File
# Begin Source File
SOURCE=.\render\texture2d.h
# End Source File
# Begin Source File
SOURCE=.\render\texturesmanager.h
# End Source File
# Begin Source File
SOURCE=.\render\vertexbuffer.h
# End Source File
# End Group

View File

@@ -44,6 +44,10 @@ void GL_CheckErrorFunction(const char* expression, const char* filename, int lin
Msg( "OpenGL Error: %s (%s) at %s:%i", expression, GL_ErrorString( err ), filename, line );// Msg("OpenGL Error: %s [%s]\n", GL_ErrorString(err), GL_TargetToString(tex->target));
}
void GL_SetTexture( int slot, uint texture )
{
}
uint GetGLBlendFactor(BlendFactor factor)
{
switch (factor)

View File

@@ -13,6 +13,8 @@ void GL_CheckError();
void GL_CheckErrorEx(const char* filename, int line);
void GL_CheckErrorFunction(const char* expression, const char* filename, int line);
void GL_SetTexture( int slot, uint texture );
#define GL_CHECK_ERROR() \
GL_CheckErrorEx(__FILE__, __LINE__)
@@ -20,6 +22,9 @@ void GL_CheckErrorFunction(const char* expression, const char* filename, int lin
expr; \
GL_CheckErrorFunction(#expr, __FILE__, __LINE__)
// OpenGL 1.3 Functional
// OpenGL 1.5 Functional
extern PFNGLGENQUERIESPROC glGenQueries;
extern PFNGLDELETEQUERIESPROC glDeleteQueries;

View File

@@ -57,6 +57,24 @@ enum PrimitiveType
PT_TRIANGLES
};
enum TextureWrap
{
TW_REPEAT,
TW_MIRROREDREPEAT,
TW_CLAMPTOEDGE,
TW_CLAMPTOBORDER
};
enum TextureFilter
{
TF_NEAREST,
TF_LINEAR,
TF_NEARESTMIPMAPNEAREST,
TF_LINEARMIPMAPNEAREST,
TF_NEARESTMIPMAPLINEAR,
TF_LINEARMIPMAPLINEAR
};
// Base structure for render view (view and projection matrices, viewport settings)
struct View
{

View File

@@ -136,11 +136,11 @@ void RenderDevice::SetReadRenderTarget(RenderTarget* renderTarget)
if (renderTarget) {
if (m_activeReadRT != renderTarget) {
m_activeReadRT = renderTarget;
//glBindFramebuffer(GL_READ_FRAMEBUFFER, renderTarget->m_framebuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER, renderTarget->m_framebuffer);
}
}
else { // set default rt
// glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
}
@@ -149,11 +149,11 @@ void RenderDevice::SetWriteRenderTarget(RenderTarget* renderTarget)
if (renderTarget) {
if (m_activeWriteRT != renderTarget) {
m_activeWriteRT = renderTarget;
//glBindFramebuffer(GL_DRAW_FRAMEBUFFER, renderTarget->m_framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, renderTarget->m_framebuffer);
}
}
else { // set default rt
//glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
}

View File

@@ -4,8 +4,6 @@
#include "render/texturesmanager.h"
#include "render/texture2d.h"
#include "glad/glad.h"
void RenderTarget::setDefaultFramebuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);

255
engine/render/texture2d.cpp Normal file
View File

@@ -0,0 +1,255 @@
#include <assert.h>
#include "render/texture2d.h"
#include "render/texturesmanager.h"
#include "render/gl_shared.h"
GLint GetGlWrap(TextureWrap wrap);
GLint GetGlTexFilter(TextureFilter filter);
Texture2D* Texture2D::Create()
{
return new Texture2D;
}
Texture2D::Texture2D()
{
m_pf = PF_UNKNOWN;
m_width = 0;
m_height = 0;
m_channels = 0;
m_handle = -1;
}
Texture2D::~Texture2D()
{
m_pf = PF_UNKNOWN;
m_width = 0;
m_height = 0;
m_channels = 0;
m_handle = -1;
}
void Texture2D::CreateBlackTexture(int width, int height, int channels)
{
size_t textureSize = width * height * channels;
byte* data = new byte[textureSize];
assert(data);
for (int i = 0; i < (int)textureSize; i++) {
data[i] = 0;
}
CreateFromExistedData(data, width, height, channels);
delete[] data;
}
void Texture2D::CreateWhiteTexture(int width, int height, int channels)
{
size_t textureSize = width * height * channels;
byte* data = new byte[textureSize];
assert(data);
for (int i = 0; i < (int)textureSize; i++) {
data[i] = 255;
}
CreateFromExistedData(data, width, height, channels);
delete[] data;
}
void Texture2D::CreateGrayTexture(int width, int height, int channels)
{
size_t textureSize = width * height * channels;
byte* data = new byte[textureSize];
assert(data);
for (int i = 0; i < (int)textureSize; i++) {
data[i] = 255 / 2;
}
CreateFromExistedData(data, width, height, channels);
delete[] data;
}
void Texture2D::CreateTexture_Generator(int width, int height, int channels, int color)
{
size_t textureSize = width * height * channels;
byte* data = new byte[textureSize];
assert(data);
m_textureFileName = "$generator_texture$";
for (int i = 0; i < (int)textureSize; i++) {
data[i] = color;
}
CreateFromExistedData(data, width, height, channels);
delete[] data;
}
void Texture2D::CreateFromExistedData(void* data, int width, int height, int channels)
{
//assert(data);
m_width = width;
m_height = height;
m_channels = channels;
glGenTextures(1, &m_handle);
glBindTexture(GL_TEXTURE_2D, m_handle);
glTexImage2D(GL_TEXTURE_2D, 0, (channels == 3) ? GL_RGB : GL_RGBA, width, height, 0, (channels == 3) ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture2D::CreateRaw(void* data, int width, int height, PixelFormat pf)
{
m_width = width;
m_height = height;
m_channels = (pf == PF_R8G8B8) ? 3 : 4;
m_pf = pf;
glGenTextures(1, &m_handle);
glBindTexture(GL_TEXTURE_2D, m_handle);
glTexImage2D(GL_TEXTURE_2D, 0, getGLInternalPF(pf), width, height, 0, getGLInternalPF(pf), GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
}
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
void Texture2D::GenerateMipmaps()
{
glBindTexture(GL_TEXTURE_2D, m_handle);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//if (g_texAnisoFilter.getValueB()) {
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, g_texAnisoLevel.getValueI());
//}
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture2D::Bind()
{
glBindTexture(GL_TEXTURE_2D, m_handle);
}
void Texture2D::SetWrapS(TextureWrap wrap)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getGlWrap(wrap));
}
void Texture2D::SetWrapT(TextureWrap wrap)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getGlWrap(wrap));
}
void Texture2D::SetMin(TextureFilter filter)
{
GLint param = 0;
param = getGlTexFilter(filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
}
void Texture2D::SetMag(TextureFilter filter)
{
GLint param = 0;
param = getGlTexFilter(filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
}
GLint GetGlWrap(TextureWrap wrap)
{
GLint param = 0;
if (wrap == TextureWrap::Repeat)
param = GL_REPEAT;
else if (wrap == TextureWrap::MirroredRepeat)
param = GL_MIRRORED_REPEAT;
else if (wrap == TextureWrap::ClampToEdge)
param = GL_CLAMP_TO_EDGE;
else if (wrap == TextureWrap::ClampToBorder)
param = GL_CLAMP_TO_BORDER;
return param;
}
GLint GetGlTexFilter(TextureFilter filter)
{
GLint param = 0;
if (filter == TextureFilter::Linear)
param = GL_LINEAR;
else if (filter == TextureFilter::Nearest)
param = GL_NEAREST;
else if (filter == TextureFilter::LinearMipmapLinear)
param = GL_LINEAR_MIPMAP_LINEAR;
else if (filter == TextureFilter::LinearMipmapNearest)
param = GL_LINEAR_MIPMAP_NEAREST;
else if (filter == TextureFilter::NearestMipmapLinear)
param = GL_NEAREST_MIPMAP_LINEAR;
else if (filter == TextureFilter::NearestMipmapNearest)
param = GL_NEAREST_MIPMAP_NEAREST;
return param;
}
uint getGLPF(PixelFormat pf)
{
return 0;
//return uint32_t();
}
// Kirill: Remove to render_main.cpp or something else
uint getGLInternalPF(PixelFormat pf)
{
switch (pf)
{
case PF_UNKNOWN:
return 0;
case PF_R8G8B8:
case PF_R8G8B8F:
return GL_RGB;
case PF_R8G8B8A8:
case PF_R8G8B8A8F:
return GL_RGBA;
}
return 0;
}
uint getGLTypePF(PixelFormat pf)
{
switch (pf)
{
case PF_UNKNOWN:
return 0;
case PF_R8G8B8:
case PF_R8G8B8A8:
return GL_UNSIGNED_BYTE;
case PF_R8G8B8F:
case PF_R8G8B8A8F:
return GL_FLOAT;
}
return 0;
}

49
engine/render/texture2d.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef TEXTURE2D_H
#define TEXTURE2D_H
#include <string>
#include "render/render_shared.h"
class TexturesManager;
class Texture2D
{
friend class TexturesManager;
public:
static Texture2D* Create();
public:
Texture2D();
~Texture2D();
void CreateBlackTexture(int width, int height, int channels);
void CreateWhiteTexture(int width, int height, int channels);
void CreateGrayTexture(int width, int height, int channels);
void CreateTexture_Generator(int width, int height, int channels, int color);
void CreateFromExistedData(void* data, int width, int height, int channels);
void CreateFromFile(const char* filename);
void CreateRaw(void* data, int width, int height, PixelFormat pf);
void GenerateMipmaps();
void Bind();
void SetWrapS(TextureWrap wrap);
void SetWrapT(TextureWrap wrap);
void SetMin(TextureFilter filter);
void SetMag(TextureFilter filter);
uint GetHandle() { return m_handle; }
private:
std::string m_textureFileName;
PixelFormat m_pf;
int m_width;
int m_height;
int m_channels;
uint m_handle;
};
#endif // !TEXTURE2D_H

View File

@@ -0,0 +1,192 @@
#include "utils/logger.h"
#include "filesystem/filemanager.h"
#include "render/texture2d.h"
#include "render/texturesmanager.h"
#include "render/gl_shared.h"
// STB Image loading code
void Texture2D::CreateFromFile(const char* filename)
{
/*
int width, height, channels;
m_textureFileName = filename;
File* file = g_fileManager->OpenFile(filename, FileAccess::Read);
file->seek(SeekDir::End, 0);
size_t imageSize = file->tell();
file->seek(SeekDir::Begin, 0);
uint8_t* fileData = (uint8_t*)malloc(imageSize);
file->read(fileData, imageSize);
g_fileManager->CloseFile(file);
uint8_t* imageData = stbi_load_from_memory(fileData, int(imageSize), &width, &height, &channels, 0);
if (imageData == NULL) {
free(fileData);
Msg("Texture loading error: %s (%s)", filename, stbi_failure_reason());
assert(imageData);
}
CreateFromExistedData(imageData, width, height, channels);
m_textureFileName = filename;
free(fileData);
stbi_image_free(imageData);
*/
}
static const char* g_texFileExtensions[] = { ".png", ".jpeg", ".jpg", ".tga", ".bmp" };
const int kTexFileExtensionsSize = sizeof(g_texFileExtensions) / sizeof(g_texFileExtensions[0]);
TexturesManager* g_texturesManager = NULL;
TexturesManager::TexturesManager()
{
m_notex = NULL;
}
TexturesManager::~TexturesManager()
{
}
void TexturesManager::Init()
{
//stbi_set_flip_vertically_on_load(true);
m_notex = LoadTexture2D("content/textures/system/notex.png", true);
if (!m_notex) {
Logger::Error("TexturesManager::Init: Failed to initialize system texture! 'system/notex.png' is not exist.");
}
}
void TexturesManager::Shutdown()
{
if (!m_textures.empty()) {
Msg("--- unfreed textures ---");
for (std::vector<Texture2D*>::iterator it = m_textures.begin(); it != m_textures.end(); ++it) {
Msg("%s", (*it)->m_textureFileName.c_str());
delete* it;
*it = NULL;
}
m_textures.clear();
}
}
void TexturesManager::SetTexture(int slot, Texture2D* texture)
{
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, texture ? texture->GetHandle() : 0);
}
Texture2D* TexturesManager::CreateManual2D(const char* name, int width, int height, PixelFormat format, bool useAsRenderTarget)
{
for (std::vector<Texture2D*>::iterator it = m_textures.begin(); it != m_textures.end(); ++it) {
if ((*it)->m_textureFileName == name) {
Logger::Error("TexturesManager::CreateManual2D: texture %s is already created!", name);
}
}
// allocate
Texture2D* texture = Texture2D::Create();
texture->CreateRaw(nullptr, width, height, format);
texture->m_textureFileName = name;
if (useAsRenderTarget)
Msg("Created rt texture [%s]", name);
return texture;
}
bool IsSupportedExtension(const char* filename)
{
std::string ext = fs::getFileExtension(filename);
for (int i = 0; i < kTexFileExtensionsSize; i++) {
if (ext == g_texFileExtensions[i]) {
return true;
}
}
return false;
}
Texture2D* TexturesManager::LoadTexture2D(const char* texturename, bool useMipmaps /*= false*/)
{
int texturesNbr = m_textures.size();
for (int i = 0; i < texturesNbr; i++) {
if (m_textures[i]->m_textureFileName == texturename)
return m_textures[i];
}
if (strcmp(texturename, "$white$") == 0) {
Texture2D* tex = Texture2D::Create();
tex->m_textureFileName = "$white$";
tex->CreateWhiteTexture(16, 16, 3);
m_textures.push_back(tex);
return tex;
}
if (strcmp(texturename, "$black$") == 0) {
Texture2D* tex = Texture2D::Create();
tex->m_textureFileName = "$black$";
tex->CreateBlackTexture(16, 16, 3);
m_textures.push_back(tex);
return tex;
}
if (strcmp(texturename, "$gray$") == 0) {
Texture2D* tex = Texture2D::Create();
tex->m_textureFileName = "$gray$";
tex->CreateGrayTexture(16, 16, 3);
m_textures.push_back(tex);
return tex;
}
if (strcmp(texturename, "$gray_console$") == 0) {
Texture2D* tex = Texture2D::Create();
tex->CreateTexture_Generator(16, 16, 3, 32);
m_textures.push_back(tex);
return tex;
}
if (strlen(texturename) <= 0) {
return m_notex;
}
std::string texnamebuf;
// find texture from disk
for (int i = 0; i < kTexFileExtensionsSize; i++)
{
std::string textureFilename = fs::getFileNameWithoutExtension(texturename);
textureFilename += g_texFileExtensions[i];
if (g_fileManager->FileExist(textureFilename.c_str()))
{
texnamebuf = textureFilename;
break;
}
}
if (!texnamebuf.empty()) {
Texture2D* texture = Texture2D::Create();
texture->CreateFromFile(texnamebuf.c_str());
if (useMipmaps)
texture->GenerateMipmaps();
Msg("loaded %s", fs::getFilenameWithoutPathAndExtension(texturename).c_str());
m_textures.push_back(texture);
return texture;
}
else if (texnamebuf.empty() && m_notex) {
Msg("not found %s", fs::getFilenameWithoutPathAndExtension(texturename).c_str());
return m_notex;
}
return NULL;
}

View File

@@ -0,0 +1,38 @@
#ifndef TEXTURESMANAGER_H
#define TEXTURESMANAGER_H
#include <vector>
#include "render/render_shared.h"
class Texture2D;
class TexturesManager
{
public:
TexturesManager();
~TexturesManager();
void Init();
void Shutdown();
void SetTexture(int slot, Texture2D* texture);
Texture2D* CreateManual2D(
const char* name,
int width,
int height,
PixelFormat format,
bool useAsRenderTarget = false);
Texture2D* LoadTexture2D(const char* texturename, bool useMipmaps = false);
private:
std::vector<Texture2D*> m_textures;
Texture2D* m_notex;
};
extern TexturesManager* g_texturesManager;
#endif // !TEXTURESMANAGER_H

141
engine/utils/rtti.h Normal file
View File

@@ -0,0 +1,141 @@
/*
The other day we tracked a bad bug where a base class was been cast to
the wrong thing.
The reason why it happed was because we didn't have any RTTI (Run Time
Type Information) in place.
We also didn't want to use the one that it comes with the compiler for
fear that it will add "evil" code.
So after hitting that bug I decided to do my on RTTI. I wanted to be
simple and very fast.
This is what we use now. It looks kind of neat so I thought to share it.
Enjoy.
Tomas
tarce@zen-x.net
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
//==============================================================================
// RTTI
//==============================================================================
// Using the RTTI
//------------------------------------------------------------------------------
// struct base
// {
// CREATE_RTTI_BASE( base );
// };
//
// struct pepe : public base
// {
// CREATE_RTTI( pepe, base, base )
// void Normal( void ){}
// };
//
// struct super_pepe : public pepe
// {
// CREATE_RTTI( super_pepe, pepe, base )
// void Super( void ){}
// };
//
// void main( void )
// {
// super_pepe SP; // The original class
// base& B = SP; // Some generic base reference
//
// // We want to safely convert to pepe
// pepe& P = pepe::GetSaveType( B );
//
// // cast the base class right
// if( B.IsKindOf( super_pepe::GetRTTI() ) )
// {
// super_pepe& SP = super_pepe::GetSaveType( B );
// SP.Super();
// }
// else if( B.IsKindOf( pepe::GetRTTI() ) )
// {
// pepe& P = pepe::GetSaveType( B );
// P.Normal();
// }
// }
//==============================================================================
#define CREATE_RTTI( TYPE, BASE_CLASS )
#define CREATE_RTTI_BASE( TYPE )
struct RTTI
{
bool IsKindOf( const RTTI& RTTI ) const;
RTTI ( const char* pTypeName );
RTTI ( const char* pTypeName, const RTTI& RTTI );
const char* pType; // This is not really need it, just useful in debugger.
const RTTI& Next;
};
//==============================================================================
// IMPLEMENTATION
//==============================================================================
#pragma warning( push )
#pragma warning( disable : 4355 ) // warning 'this' used in base member initializer list
#undef CREATE_RTTI
#undef CREATE_RTTI_BASE
inline RTTI::RTTI( const char* pTypeName ) :
pType(pTypeName), Next( *this ){}
inline RTTI::RTTI( const char* pTypeName, const RTTI& RTTI ) :
pType(pTypeName), Next( RTTI ){}
inline bool RTTI::IsKindOf( const RTTI& RTTI ) const
{
const RTTI* p = this;
do
{
if( p == &RTTI ) return true;
if( p == &p->Next ) break;
p = &p->Next;
} while(1);
return false;
}
#define PRIVATE_RTTI_FUNCTION_SET( TYPE, BASE_CLASS ) \
virtual inline const RTTI& GetObjectRTTI( void ) const \
{ \
return TYPE::GetRTTI(); \
} \
inline const bool IsKindOf( const RTTI& RTTI ) const \
{ \
return GetObjectRTTI().IsKindOf( RTTI ); \
} \
static inline TYPE& GetSaveType( BASE_CLASS& Object ) \
{ \
assert( Object.IsKindOf(TYPE::GetRTTI()) ); \
return *((TYPE*)&Object); \
} \
static inline const TYPE& GetSaveType( const BASE_CLASS& Object ) \
{ \
assert( Object.IsKindOf(TYPE::GetRTTI()) ); \
return *((const TYPE*)&Object); \
}
#define CREATE_RTTI( TYPE, TYPE_PARENT, BASE_CLASS ) \
static inline const RTTI& GetRTTI( void ) \
{ \
static RTTI s_RTTI( #TYPE, TYPE_PARENT::GetRTTI() ); \
return s_RTTI; \
} \
PRIVATE_RTTI_FUNCTION_SET(TYPE,BASE_CLASS)
#define CREATE_RTTI_BASE( TYPE ) \
static inline const RTTI& GetRTTI( void ) \
{ \
static RTTI s_RTTI( #TYPE ); \
return s_RTTI; \
} \
PRIVATE_RTTI_FUNCTION_SET(TYPE,TYPE)
#pragma warning( pop )