Refactor engine code
This commit is contained in:
6
.vscode/c_cpp_properties.json
vendored
6
.vscode/c_cpp_properties.json
vendored
@@ -3,9 +3,9 @@
|
|||||||
{
|
{
|
||||||
"name": "Linux",
|
"name": "Linux",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${workspaceFolder}/Ps1Engine/renderer",
|
"${workspaceFolder}/Engine/renderer",
|
||||||
"${workspaceFolder}/Ps1Engine/loader",
|
"${workspaceFolder}/Engine/loader",
|
||||||
"${workspaceFolder}/Ps1Engine",
|
"${workspaceFolder}/Engine",
|
||||||
"${workspaceFolder}/external/**",
|
"${workspaceFolder}/external/**",
|
||||||
"/usr/include",
|
"/usr/include",
|
||||||
"/usr/local/include"
|
"/usr/local/include"
|
||||||
|
|||||||
16
.vscode/settings.json
vendored
16
.vscode/settings.json
vendored
@@ -63,6 +63,20 @@
|
|||||||
"streambuf": "cpp",
|
"streambuf": "cpp",
|
||||||
"cinttypes": "cpp",
|
"cinttypes": "cpp",
|
||||||
"typeinfo": "cpp",
|
"typeinfo": "cpp",
|
||||||
"variant": "cpp"
|
"variant": "cpp",
|
||||||
|
"csignal": "cpp",
|
||||||
|
"strstream": "cpp",
|
||||||
|
"bitset": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"unordered_set": "cpp",
|
||||||
|
"expected": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"ranges": "cpp",
|
||||||
|
"semaphore": "cpp",
|
||||||
|
"shared_mutex": "cpp",
|
||||||
|
"stop_token": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"typeindex": "cpp",
|
||||||
|
"valarray": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,23 +8,25 @@ set(CMAKE_CXX_STANDARD 17)
|
|||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
# Include directories
|
# Include directories
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/renderer)
|
include_directories(${CMAKE_SOURCE_DIR}/Engine)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/loader)
|
include_directories(${CMAKE_SOURCE_DIR}/Engine/renderer)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/Engine/loader)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/examples)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/external/stb)
|
include_directories(${CMAKE_SOURCE_DIR}/external/stb)
|
||||||
|
|
||||||
# Source files
|
# Source files
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
${CMAKE_SOURCE_DIR}/renderer/renderer.cpp
|
${CMAKE_SOURCE_DIR}/Engine/renderer/renderer.cpp
|
||||||
${CMAKE_SOURCE_DIR}/loader/mesh.cpp
|
${CMAKE_SOURCE_DIR}/Engine/loader/mesh.cpp
|
||||||
${CMAKE_SOURCE_DIR}/../cube.cpp
|
${CMAKE_SOURCE_DIR}/examples/cube.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Executable
|
# Executable
|
||||||
add_executable(Ps1Engine ${SOURCES})
|
add_executable(Engine ${SOURCES})
|
||||||
|
|
||||||
# Link libraries
|
# Link libraries
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
find_package(GLEW REQUIRED)
|
find_package(GLEW REQUIRED)
|
||||||
find_package(glfw3 REQUIRED)
|
find_package(glfw3 REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(Ps1Engine OpenGL::GL GLEW::GLEW glfw)
|
target_link_libraries(Engine OpenGL::GL GLEW::GLEW glfw)
|
||||||
@@ -7,13 +7,13 @@
|
|||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
std::map<std::string, Color> load_mtl_colors(const std::string& mtl_path)
|
std::map<std::string, Material> load_mtl_materials(const std::string& mtl_path)
|
||||||
{
|
{
|
||||||
std::map<std::string, Color> material_colors;
|
std::map<std::string, Material> materials;
|
||||||
std::ifstream file(mtl_path);
|
std::ifstream file(mtl_path);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
std::cerr << "Warning: could not open MTL file: " << mtl_path << std::endl;
|
std::cerr << "Warning: could not open MTL file: " << mtl_path << std::endl;
|
||||||
return material_colors;
|
return materials;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string line, current_mtl;
|
std::string line, current_mtl;
|
||||||
@@ -24,21 +24,30 @@ std::map<std::string, Color> load_mtl_colors(const std::string& mtl_path)
|
|||||||
|
|
||||||
if (keyword == "newmtl") {
|
if (keyword == "newmtl") {
|
||||||
ss >> current_mtl;
|
ss >> current_mtl;
|
||||||
|
materials[current_mtl] = Material{Color(255, 255, 255), ""}; // Default white, no texture
|
||||||
} else if (keyword == "Kd") {
|
} else if (keyword == "Kd") {
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
ss >> r >> g >> b;
|
ss >> r >> g >> b;
|
||||||
material_colors[current_mtl] = Color(
|
if (materials.count(current_mtl)) {
|
||||||
static_cast<uint8_t>(r * 255),
|
materials[current_mtl].color = Color(
|
||||||
static_cast<uint8_t>(g * 255),
|
static_cast<uint8_t>(r * 255),
|
||||||
static_cast<uint8_t>(b * 255)
|
static_cast<uint8_t>(g * 255),
|
||||||
);
|
static_cast<uint8_t>(b * 255)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (keyword == "map_Kd") {
|
||||||
|
std::string texture_path;
|
||||||
|
ss >> texture_path;
|
||||||
|
if (materials.count(current_mtl)) {
|
||||||
|
materials[current_mtl].texture_path = texture_path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return material_colors;
|
return materials;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Triangle> load_obj(const std::string& obj_path)
|
std::vector<Triangle> load_obj(const std::string& obj_path, Renderer* renderer)
|
||||||
{
|
{
|
||||||
std::ifstream file(obj_path);
|
std::ifstream file(obj_path);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
@@ -47,7 +56,8 @@ std::vector<Triangle> load_obj(const std::string& obj_path)
|
|||||||
|
|
||||||
std::vector<Vec3> positions;
|
std::vector<Vec3> positions;
|
||||||
std::vector<Vec2> texcoords;
|
std::vector<Vec2> texcoords;
|
||||||
std::map<std::string, Color> materials;
|
std::map<std::string, Material> materials;
|
||||||
|
std::map<std::string, GLuint> texture_map;
|
||||||
std::vector<Triangle> triangles;
|
std::vector<Triangle> triangles;
|
||||||
|
|
||||||
std::string current_material = "";
|
std::string current_material = "";
|
||||||
@@ -100,9 +110,11 @@ std::vector<Triangle> load_obj(const std::string& obj_path)
|
|||||||
tri.uv2 = (t_idx[i + 1] >= 0 && t_idx[i + 1] < (int)texcoords.size()) ? texcoords[t_idx[i + 1]] : Vec2(0, 0);
|
tri.uv2 = (t_idx[i + 1] >= 0 && t_idx[i + 1] < (int)texcoords.size()) ? texcoords[t_idx[i + 1]] : Vec2(0, 0);
|
||||||
|
|
||||||
if (materials.count(current_material)) {
|
if (materials.count(current_material)) {
|
||||||
tri.color = materials[current_material];
|
tri.color = materials[current_material].color;
|
||||||
|
tri.texture = texture_map[current_material];
|
||||||
} else {
|
} else {
|
||||||
tri.color = Color(255, 255, 255); // fallback white
|
tri.color = Color(255, 255, 255); // Fallback white
|
||||||
|
tri.texture = 0; // No texture
|
||||||
}
|
}
|
||||||
|
|
||||||
triangles.push_back(tri);
|
triangles.push_back(tri);
|
||||||
@@ -111,7 +123,19 @@ std::vector<Triangle> load_obj(const std::string& obj_path)
|
|||||||
std::string mtl_file;
|
std::string mtl_file;
|
||||||
ss >> mtl_file;
|
ss >> mtl_file;
|
||||||
fs::path mtl_path = base_path / mtl_file;
|
fs::path mtl_path = base_path / mtl_file;
|
||||||
materials = load_mtl_colors(mtl_path.string());
|
materials = load_mtl_materials(mtl_path.string());
|
||||||
|
|
||||||
|
// Load textures for all materials
|
||||||
|
for (const auto& mat_pair : materials) {
|
||||||
|
const std::string& mat_name = mat_pair.first;
|
||||||
|
const Material& mat = mat_pair.second;
|
||||||
|
if (!mat.texture_path.empty()) {
|
||||||
|
fs::path texture_full_path = base_path / mat.texture_path;
|
||||||
|
texture_map[mat_name] = renderer->load_texture(texture_full_path.string());
|
||||||
|
} else {
|
||||||
|
texture_map[mat_name] = 0; // No texture
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (keyword == "usemtl") {
|
} else if (keyword == "usemtl") {
|
||||||
ss >> current_material;
|
ss >> current_material;
|
||||||
}
|
}
|
||||||
15
Engine/loader/mesh.h
Normal file
15
Engine/loader/mesh.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "renderer.h" // includes Vec3, Vec2, Triangle, Color
|
||||||
|
|
||||||
|
struct Material
|
||||||
|
{
|
||||||
|
Color color;
|
||||||
|
std::string texture_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, Material> load_mtl_materials(const std::string& mtl_path);
|
||||||
|
std::vector<Triangle> load_obj(const std::string& obj_path, Renderer* renderer);
|
||||||
2
Engine/ps1engine.h
Normal file
2
Engine/ps1engine.h
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#include <renderer.h>
|
||||||
|
#include <mesh.h>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
@@ -50,7 +51,6 @@ Matrix4 matrix_multiply(const Matrix4 &a, const Matrix4 &b)
|
|||||||
|
|
||||||
Color convert_color(const Color &color)
|
Color convert_color(const Color &color)
|
||||||
{
|
{
|
||||||
|
|
||||||
uint8_t r = (color.r >> 3) << 3;
|
uint8_t r = (color.r >> 3) << 3;
|
||||||
uint8_t g = (color.g >> 3) << 3;
|
uint8_t g = (color.g >> 3) << 3;
|
||||||
uint8_t b = (color.b >> 3) << 3;
|
uint8_t b = (color.b >> 3) << 3;
|
||||||
@@ -61,7 +61,6 @@ Renderer::Renderer(int width_, int height_, const std::string &title_)
|
|||||||
: width(width_), height(height_), title(title_),
|
: width(width_), height(height_), title(title_),
|
||||||
internal_width(320), internal_height(240)
|
internal_width(320), internal_height(240)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!glfwInit())
|
if (!glfwInit())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to initialize GLFW");
|
throw std::runtime_error("Failed to initialize GLFW");
|
||||||
@@ -105,12 +104,11 @@ void Renderer::set_view_matrix(const Matrix4 &view)
|
|||||||
|
|
||||||
void Renderer::begin_frame()
|
void Renderer::begin_frame()
|
||||||
{
|
{
|
||||||
|
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::render(const std::vector<Triangle> &triangles, GLuint texture)
|
void Renderer::render(const std::vector<Triangle> &triangles)
|
||||||
{
|
{
|
||||||
std::vector<Triangle> transformed_triangles;
|
std::vector<Triangle> transformed_triangles;
|
||||||
|
|
||||||
@@ -124,6 +122,7 @@ void Renderer::render(const std::vector<Triangle> &triangles, GLuint texture)
|
|||||||
t.uv1 = tri.uv1;
|
t.uv1 = tri.uv1;
|
||||||
t.uv2 = tri.uv2;
|
t.uv2 = tri.uv2;
|
||||||
t.color = tri.color;
|
t.color = tri.color;
|
||||||
|
t.texture = tri.texture;
|
||||||
|
|
||||||
Vec3 edge1(t.v1.x - t.v0.x, t.v1.y - t.v0.y, t.v1.z - t.v0.z);
|
Vec3 edge1(t.v1.x - t.v0.x, t.v1.y - t.v0.y, t.v1.z - t.v0.z);
|
||||||
Vec3 edge2(t.v2.x - t.v0.x, t.v2.y - t.v0.y, t.v2.z - t.v0.z);
|
Vec3 edge2(t.v2.x - t.v0.x, t.v2.y - t.v0.y, t.v2.z - t.v0.z);
|
||||||
@@ -185,53 +184,81 @@ void Renderer::render(const std::vector<Triangle> &triangles, GLuint texture)
|
|||||||
screen_tri.uv1 = tri.uv1;
|
screen_tri.uv1 = tri.uv1;
|
||||||
screen_tri.uv2 = tri.uv2;
|
screen_tri.uv2 = tri.uv2;
|
||||||
screen_tri.color = convert_color(tri.color);
|
screen_tri.color = convert_color(tri.color);
|
||||||
|
screen_tri.texture = tri.texture;
|
||||||
|
|
||||||
screen_triangles.push_back(screen_tri);
|
screen_triangles.push_back(screen_tri);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
// Group triangles by texture
|
||||||
|
std::map<GLuint, std::vector<Triangle>> texture_groups;
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
for (const auto& tri : screen_triangles)
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
{
|
||||||
|
texture_groups[tri.texture].push_back(tri);
|
||||||
|
}
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
for (const auto &tri : screen_triangles)
|
// Render each texture group
|
||||||
|
for (const auto& group : texture_groups)
|
||||||
{
|
{
|
||||||
|
GLuint tex = group.first;
|
||||||
|
const std::vector<Triangle>& tris = group.second;
|
||||||
|
|
||||||
glBegin(GL_TRIANGLES);
|
if (tex != 0)
|
||||||
|
{
|
||||||
Color c = tri.color;
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
glColor3ub(c.r, c.g, c.b);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexCoord2f(tri.uv0.x, tri.uv0.y);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glVertex3f(static_cast<float>(tri.v0.x), static_cast<float>(tri.v0.y), static_cast<float>(tri.v0.z) / 32767.0f);
|
}
|
||||||
|
else
|
||||||
glTexCoord2f(tri.uv1.x, tri.uv1.y);
|
|
||||||
glVertex3f(static_cast<float>(tri.v1.x), static_cast<float>(tri.v1.y), static_cast<float>(tri.v1.z) / 32767.0f);
|
|
||||||
|
|
||||||
glTexCoord2f(tri.uv2.x, tri.uv2.y);
|
|
||||||
glVertex3f(static_cast<float>(tri.v2.x), static_cast<float>(tri.v2.y), static_cast<float>(tri.v2.z) / 32767.0f);
|
|
||||||
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
if (rand() % 5 == 0)
|
|
||||||
{
|
{
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
glColor3f(0.0f, 0.0f, 0.0f);
|
}
|
||||||
glBegin(GL_LINE_LOOP);
|
|
||||||
|
for (const auto& tri : tris)
|
||||||
|
{
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
Color c = tri.color;
|
||||||
|
glColor3ub(c.r, c.g, c.b);
|
||||||
|
|
||||||
|
if (tex != 0)
|
||||||
|
{
|
||||||
|
glTexCoord2f(tri.uv0.x, tri.uv0.y);
|
||||||
|
}
|
||||||
glVertex3f(static_cast<float>(tri.v0.x), static_cast<float>(tri.v0.y), static_cast<float>(tri.v0.z) / 32767.0f);
|
glVertex3f(static_cast<float>(tri.v0.x), static_cast<float>(tri.v0.y), static_cast<float>(tri.v0.z) / 32767.0f);
|
||||||
|
|
||||||
|
if (tex != 0)
|
||||||
|
{
|
||||||
|
glTexCoord2f(tri.uv1.x, tri.uv1.y);
|
||||||
|
}
|
||||||
glVertex3f(static_cast<float>(tri.v1.x), static_cast<float>(tri.v1.y), static_cast<float>(tri.v1.z) / 32767.0f);
|
glVertex3f(static_cast<float>(tri.v1.x), static_cast<float>(tri.v1.y), static_cast<float>(tri.v1.z) / 32767.0f);
|
||||||
|
|
||||||
|
if (tex != 0)
|
||||||
|
{
|
||||||
|
glTexCoord2f(tri.uv2.x, tri.uv2.y);
|
||||||
|
}
|
||||||
glVertex3f(static_cast<float>(tri.v2.x), static_cast<float>(tri.v2.y), static_cast<float>(tri.v2.z) / 32767.0f);
|
glVertex3f(static_cast<float>(tri.v2.x), static_cast<float>(tri.v2.y), static_cast<float>(tri.v2.z) / 32767.0f);
|
||||||
|
|
||||||
glEnd();
|
glEnd();
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
|
if (rand() % 5 == 0)
|
||||||
|
{
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glColor3f(0.0f, 0.0f, 0.0f);
|
||||||
|
glBegin(GL_LINE_LOOP);
|
||||||
|
glVertex3f(static_cast<float>(tri.v0.x), static_cast<float>(tri.v0.y), static_cast<float>(tri.v0.z) / 32767.0f);
|
||||||
|
glVertex3f(static_cast<float>(tri.v1.x), static_cast<float>(tri.v1.y), static_cast<float>(tri.v1.z) / 32767.0f);
|
||||||
|
glVertex3f(static_cast<float>(tri.v2.x), static_cast<float>(tri.v2.y), static_cast<float>(tri.v2.z) / 32767.0f);
|
||||||
|
glEnd();
|
||||||
|
if (tex != 0) glEnable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::end_frame()
|
void Renderer::end_frame()
|
||||||
{
|
{
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,7 @@ struct Triangle
|
|||||||
Vec3 v0, v1, v2;
|
Vec3 v0, v1, v2;
|
||||||
Vec2 uv0, uv1, uv2;
|
Vec2 uv0, uv1, uv2;
|
||||||
Color color;
|
Color color;
|
||||||
|
GLuint texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
Vec3 matrix_multiply(const Matrix4 &mat, const Vec3 &v);
|
Vec3 matrix_multiply(const Matrix4 &mat, const Vec3 &v);
|
||||||
@@ -60,10 +61,11 @@ public:
|
|||||||
~Renderer();
|
~Renderer();
|
||||||
void set_view_matrix(const Matrix4 &view);
|
void set_view_matrix(const Matrix4 &view);
|
||||||
void begin_frame();
|
void begin_frame();
|
||||||
void render(const std::vector<Triangle> &triangles, GLuint texture);
|
void render(const std::vector<Triangle> &triangles);
|
||||||
void end_frame();
|
void end_frame();
|
||||||
bool should_close();
|
bool should_close();
|
||||||
GLuint load_texture(const std::string &filepath);
|
GLuint load_texture(const std::string &filepath);
|
||||||
|
GLFWwindow *get_window() { return window; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include "renderer.h" // includes Vec3, Vec2, Triangle, Color
|
|
||||||
|
|
||||||
std::vector<Triangle> load_obj(const std::string& obj_path);
|
|
||||||
std::map<std::string, Color> load_mtl_colors(const std::string& mtl_path);
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "renderer.h"
|
#include <ps1engine.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -283,10 +283,11 @@ int main()
|
|||||||
t.uv1 = tri.uv1;
|
t.uv1 = tri.uv1;
|
||||||
t.uv2 = tri.uv2;
|
t.uv2 = tri.uv2;
|
||||||
t.color = tri.color;
|
t.color = tri.color;
|
||||||
|
t.texture = texture;
|
||||||
transformed_cube.push_back(t);
|
transformed_cube.push_back(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.render(transformed_cube, texture);
|
renderer.render(transformed_cube);
|
||||||
|
|
||||||
renderer.end_frame();
|
renderer.end_frame();
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user