Port lightmapper to java

This commit is contained in:
Alexander Klingenbeck 2023-06-19 23:24:30 +02:00
parent 5eee29160c
commit 5adc402c26
10 changed files with 768 additions and 547 deletions

View File

@ -41,8 +41,4 @@ add_executable(${CMAKE_PROJECT_NAME} ${files})
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE include)
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE src)
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE thirdparty/raygui/src)
target_link_libraries(${CMAKE_PROJECT_NAME} quickjs raylib)
add_executable(lightmapper_example src/lightmapper_example.c)
target_include_directories(lightmapper_example PRIVATE include)
target_link_libraries(lightmapper_example raylib lightmapper)
target_link_libraries(${CMAKE_PROJECT_NAME} quickjs raylib lightmapper)

View File

@ -68,6 +68,30 @@ function main(){
const reasingsFunctions = parser.parseFunctions(reasingsHeader);
reasingsFunctions.forEach(x => api.functions.push(x))
const rlightmapperHeader = readFileSync("src/rlightmapper.h", "utf8");
const rlightmapperFunctions = parser.parseFunctionDefinitions(rlightmapperHeader);
const rlightmapperStructs = parser.parseStructs(rlightmapperHeader);
rlightmapperFunctions.forEach(x => api.functions.push(x));
rlightmapperStructs.forEach(x => api.structs.push(x));
rlightmapperStructs[0].binding = {
properties: {
w: { get: true },
h: { get: true },
progress: { get: true }
}
}
rlightmapperStructs[1].binding = {
properties: {
hemisphereSize: { get: true, set: true },
zNear: { get: true, set: true },
zFar: { get: true, set: true },
backgroundColor: { get: true, set: true },
interpolationPasses: { get: true, set: true },
interpolationThreshold: { get: true, set: true },
cameraToSurfaceDistanceModifier: { get: true, set: true },
}
}
// Custom Rayjs functions
api.functions.push({
name: "SetModelMaterial",
@ -87,6 +111,12 @@ function main(){
returnType: "Color",
params: [{type: "Image *",name:"image"},{type:"int",name:"x"},{type:"int",name:"y"}]
})
api.functions.push({
name: "GetModelMesh",
description: "Get a single mesh from a model",
returnType: "Mesh",
params: [{type: "Model *",name:"model"},{type:"int",name:"meshIndex"}]
})
// Define a new header
const core = new RayLibHeader("raylib_core")
@ -97,6 +127,8 @@ function main(){
core.includes.line("#define RLIGHTS_IMPLEMENTATION")
core.includes.include("rlights.h")
core.includes.include("reasings.h")
core.includes.line("#define RLIGHTMAPPER_IMPLEMENTATION")
core.includes.include("rlightmapper.h")
getStruct(api.structs, "Color")!.binding = {
properties: {

View File

@ -0,0 +1,88 @@
function drawScene(scene){
drawModel(scene.raylib_model, new Vector3(0,0,0), 1, WHITE);
}
setConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI | FLAG_VSYNC_HINT);
initWindow(1024,768,"Test");
const scene = {}
scene.raylib_model = loadModel("models/resources/models/obj/bridge.obj");
scene.w = 512;
scene.h = 512;
scene.raylib_texture = loadTextureFromImage(genImageColor(1,1,BLACK));
const defMat = loadMaterialDefault();
setMaterialTexture(defMat, MATERIAL_MAP_ALBEDO, scene.raylib_texture);
setModelMaterial(scene.raylib_model, 0, defMat);
const position = new Vector3( 0.0, 10.0, 30.0 ); // Camera position
const target = new Vector3( 0.0, 0.35, 0.0); // Camera looking at point
const up = new Vector3(0.0, 1.0, 0.0); // Camera up vector (rotation towards target)
const fovy = 45.0; // Camera field-of-view Y
const projection = CAMERA_PERSPECTIVE; // Camera mode type
scene.camera = new Camera3D(position, target, up, fovy, projection);
const config = getDefaultLightmapperConfig();
//config.backgroundColor = new Color(6,0,10);
//config.hemisphereSize = 512;
const mesh = getModelMesh(scene.raylib_model, 0);
const lm = loadLightmapper(scene.w, scene.h, mesh, config);
const lmMat = loadMaterialLightmapper(BLACK, 0);
const light = genMeshCube(0.2,0.2,0.2);
const lightMaterial = loadMaterialLightmapper(ORANGE, 0.005);
while (!windowShouldClose())
{
if(isMouseButtonDown(MOUSE_BUTTON_LEFT))
updateCamera(scene.camera, CAMERA_THIRD_PERSON);
if(lm.progress < 1.0){
let startTime = getTime();
beginLightmap();
while(beginLightmapFragment(lm)){
drawMesh(mesh, lmMat, matrixIdentity());
// drawMesh(light, lightMaterial, matrixTranslate(0.0,0.3,0.5));
// drawMesh(light, lightMaterial, matrixTranslate(0.0,0.3,-0.5));
// drawMesh(light, lightMaterial, matrixMultiply(matrixScale(2,1,2), matrixTranslate(0.0,1.3,0)));
// drawMesh(light, lightMaterial, matrixTranslate(0.5,0.3,0));
// drawMesh(light, lightMaterial, matrixTranslate(-0.5,0.3,0));
endLightmapFragment(lm);
// display progress every second (printf is expensive)
let time = getTime();
if (getTime() - startTime > 0.03) break;
}
endLightmap();
if(lm.progress == 1.0){
const img = loadImageFromLightmapper(lm);
//exportImage(img, "my_result.png");
const old = scene.raylib_texture;
scene.raylib_texture = loadTextureFromImage(img);
unloadTexture(old);
let mat = loadMaterialDefault();
setMaterialTexture(mat, MATERIAL_MAP_DIFFUSE, scene.raylib_texture);
setModelMaterial(scene.raylib_model, 0, mat);
unloadLightmapper(lm);
}
}
beginDrawing();
clearBackground(BLUE);
beginMode3D(scene.camera);
//float intensity = 1.0f;
//SetShaderValue(scene.shader, scene.u_intensity, &intensity, SHADER_UNIFORM_FLOAT);
drawScene(scene);
endMode3D();
// printf("%d\n",(int)(lm.progress*GetScreenWidth()));
if(lm.progress < 1.0){
drawRectangle(0,0,getScreenWidth(),20, fade(GREEN,0.5));
drawRectangle(0,0,getScreenWidth()*lm.progress,20, GREEN);
}
endDrawing();
}
unloadModel(scene.raylib_model);
unloadTexture(scene.raylib_texture);
closeWindow();

View File

@ -361,6 +361,26 @@ interface Light {
declare var Light: {
prototype: Light;
}
interface Lightmapper {
w: number,
h: number,
progress: number,
}
declare var Lightmapper: {
prototype: Lightmapper;
}
interface LightmapperConfig {
hemisphereSize: number,
zNear: number,
zFar: number,
backgroundColor: Color,
interpolationPasses: number,
interpolationThreshold: number,
cameraToSurfaceDistanceModifier: number,
}
declare var LightmapperConfig: {
prototype: LightmapperConfig;
}
/** Initialize window and OpenGL context */
declare function initWindow(width: number, height: number, title: string | undefined | null): void;
/** Check if KEY_ESCAPE pressed or Close icon pressed */
@ -1616,12 +1636,32 @@ declare function easeBounceOut(t: number, b: number, c: number, d: number): numb
declare function easeBounceInOut(t: number, b: number, c: number, d: number): number;
/** Elastic Easing functions */
declare function easeElasticIn(t: number, b: number, c: number, d: number): number;
/** */
declare function getDefaultLightmapperConfig(): LightmapperConfig;
/** */
declare function loadLightmapper(w: number, h: number, mesh: Mesh, cfg: LightmapperConfig): Lightmapper;
/** */
declare function loadMaterialLightmapper(emissiveColor: Color, intensity: number): Material;
/** */
declare function unloadLightmapper(lm: Lightmapper): void;
/** */
declare function beginLightmap(): void;
/** */
declare function endLightmap(): void;
/** */
declare function beginLightmapFragment(lm: Lightmapper): boolean;
/** */
declare function endLightmapFragment(lm: Lightmapper): void;
/** */
declare function loadImageFromLightmapper(lm: Lightmapper): Image;
/** Replace material in slot materialIndex */
declare function setModelMaterial(model: Model, materialIndex: number, material: Material): void;
/** Set shader constant in shader locations array */
declare function setShaderLocation(shader: Shader, shaderConstant: number, location: number): void;
/** Read a single pixel from an image */
declare function imageReadPixel(image: Image, x: number, y: number): Color;
/** Get a single mesh from a model */
declare function getModelMesh(model: Model, meshIndex: number): Mesh;
/** (PI/180.0) */
declare var DEG2RAD: number;
/** (180.0/PI) */

View File

@ -1009,6 +1009,29 @@ function main() {
const reasingsHeader = (0, fs_1.readFileSync)("include/reasings.h", "utf8");
const reasingsFunctions = parser.parseFunctions(reasingsHeader);
reasingsFunctions.forEach(x => api.functions.push(x));
const rlightmapperHeader = (0, fs_1.readFileSync)("src/rlightmapper.h", "utf8");
const rlightmapperFunctions = parser.parseFunctionDefinitions(rlightmapperHeader);
const rlightmapperStructs = parser.parseStructs(rlightmapperHeader);
rlightmapperFunctions.forEach(x => api.functions.push(x));
rlightmapperStructs.forEach(x => api.structs.push(x));
rlightmapperStructs[0].binding = {
properties: {
w: { get: true },
h: { get: true },
progress: { get: true }
}
};
rlightmapperStructs[1].binding = {
properties: {
hemisphereSize: { get: true, set: true },
zNear: { get: true, set: true },
zFar: { get: true, set: true },
backgroundColor: { get: true, set: true },
interpolationPasses: { get: true, set: true },
interpolationThreshold: { get: true, set: true },
cameraToSurfaceDistanceModifier: { get: true, set: true },
}
};
// Custom Rayjs functions
api.functions.push({
name: "SetModelMaterial",
@ -1028,6 +1051,12 @@ function main() {
returnType: "Color",
params: [{ type: "Image *", name: "image" }, { type: "int", name: "x" }, { type: "int", name: "y" }]
});
api.functions.push({
name: "GetModelMesh",
description: "Get a single mesh from a model",
returnType: "Mesh",
params: [{ type: "Model *", name: "model" }, { type: "int", name: "meshIndex" }]
});
// Define a new header
const core = new raylib_header_1.RayLibHeader("raylib_core");
core.includes.include("raymath.h");
@ -1037,6 +1066,8 @@ function main() {
core.includes.line("#define RLIGHTS_IMPLEMENTATION");
core.includes.include("rlights.h");
core.includes.include("reasings.h");
core.includes.line("#define RLIGHTMAPPER_IMPLEMENTATION");
core.includes.include("rlightmapper.h");
getStruct(api.structs, "Color").binding = {
properties: {
r: { get: true, set: true },

View File

@ -14,6 +14,8 @@
#define RLIGHTS_IMPLEMENTATION
#include <rlights.h>
#include <reasings.h>
#define RLIGHTMAPPER_IMPLEMENTATION
#include <rlightmapper.h>
#ifndef countof
#define countof(x) (sizeof(x) / sizeof((x)[0]))
@ -53,6 +55,8 @@ static JSClassID js_VrDeviceInfo_class_id;
static JSClassID js_VrStereoConfig_class_id;
static JSClassID js_FilePathList_class_id;
static JSClassID js_Light_class_id;
static JSClassID js_Lightmapper_class_id;
static JSClassID js_LightmapperConfig_class_id;
static void js_Vector2_finalizer(JSRuntime * rt, JSValue val) {
Vector2* ptr = JS_GetOpaque(val, js_Vector2_class_id);
@ -2095,6 +2099,192 @@ static int js_declare_Light(JSContext * ctx, JSModuleDef * m) {
return 0;
}
static void js_Lightmapper_finalizer(JSRuntime * rt, JSValue val) {
Lightmapper* ptr = JS_GetOpaque(val, js_Lightmapper_class_id);
if(ptr) {
js_free_rt(rt, ptr);
}
}
static JSValue js_Lightmapper_get_w(JSContext* ctx, JSValueConst this_val) {
Lightmapper* ptr = JS_GetOpaque2(ctx, this_val, js_Lightmapper_class_id);
int w = ptr->w;
JSValue ret = JS_NewInt32(ctx, w);
return ret;
}
static JSValue js_Lightmapper_get_h(JSContext* ctx, JSValueConst this_val) {
Lightmapper* ptr = JS_GetOpaque2(ctx, this_val, js_Lightmapper_class_id);
int h = ptr->h;
JSValue ret = JS_NewInt32(ctx, h);
return ret;
}
static JSValue js_Lightmapper_get_progress(JSContext* ctx, JSValueConst this_val) {
Lightmapper* ptr = JS_GetOpaque2(ctx, this_val, js_Lightmapper_class_id);
float progress = ptr->progress;
JSValue ret = JS_NewFloat64(ctx, progress);
return ret;
}
static const JSCFunctionListEntry js_Lightmapper_proto_funcs[] = {
JS_CGETSET_DEF("w",js_Lightmapper_get_w,NULL),
JS_CGETSET_DEF("h",js_Lightmapper_get_h,NULL),
JS_CGETSET_DEF("progress",js_Lightmapper_get_progress,NULL),
JS_PROP_STRING_DEF("[Symbol.toStringTag]","Lightmapper", JS_PROP_CONFIGURABLE),
};
static int js_declare_Lightmapper(JSContext * ctx, JSModuleDef * m) {
JS_NewClassID(&js_Lightmapper_class_id);
JSClassDef js_Lightmapper_def = { .class_name = "Lightmapper", .finalizer = js_Lightmapper_finalizer };
JS_NewClass(JS_GetRuntime(ctx), js_Lightmapper_class_id, &js_Lightmapper_def);
JSValue proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, proto, js_Lightmapper_proto_funcs, countof(js_Lightmapper_proto_funcs));
JS_SetClassProto(ctx, js_Lightmapper_class_id, proto);
return 0;
}
static void js_LightmapperConfig_finalizer(JSRuntime * rt, JSValue val) {
LightmapperConfig* ptr = JS_GetOpaque(val, js_LightmapperConfig_class_id);
if(ptr) {
js_free_rt(rt, ptr);
}
}
static JSValue js_LightmapperConfig_get_hemisphereSize(JSContext* ctx, JSValueConst this_val) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
int hemisphereSize = ptr->hemisphereSize;
JSValue ret = JS_NewInt32(ctx, hemisphereSize);
return ret;
}
static JSValue js_LightmapperConfig_set_hemisphereSize(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
int value;
JS_ToInt32(ctx, &value, v);
ptr->hemisphereSize = value;
return JS_UNDEFINED;
}
static JSValue js_LightmapperConfig_get_zNear(JSContext* ctx, JSValueConst this_val) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
float zNear = ptr->zNear;
JSValue ret = JS_NewFloat64(ctx, zNear);
return ret;
}
static JSValue js_LightmapperConfig_set_zNear(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
double _double_value;
JS_ToFloat64(ctx, &_double_value, v);
float value = (float)_double_value;
ptr->zNear = value;
return JS_UNDEFINED;
}
static JSValue js_LightmapperConfig_get_zFar(JSContext* ctx, JSValueConst this_val) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
float zFar = ptr->zFar;
JSValue ret = JS_NewFloat64(ctx, zFar);
return ret;
}
static JSValue js_LightmapperConfig_set_zFar(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
double _double_value;
JS_ToFloat64(ctx, &_double_value, v);
float value = (float)_double_value;
ptr->zFar = value;
return JS_UNDEFINED;
}
static JSValue js_LightmapperConfig_get_backgroundColor(JSContext* ctx, JSValueConst this_val) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
Color backgroundColor = ptr->backgroundColor;
Color* ret_ptr = (Color*)js_malloc(ctx, sizeof(Color));
*ret_ptr = backgroundColor;
JSValue ret = JS_NewObjectClass(ctx, js_Color_class_id);
JS_SetOpaque(ret, ret_ptr);
return ret;
}
static JSValue js_LightmapperConfig_set_backgroundColor(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
Color* value_ptr = (Color*)JS_GetOpaque2(ctx, v, js_Color_class_id);
if(value_ptr == NULL) return JS_EXCEPTION;
Color value = *value_ptr;
ptr->backgroundColor = value;
return JS_UNDEFINED;
}
static JSValue js_LightmapperConfig_get_interpolationPasses(JSContext* ctx, JSValueConst this_val) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
int interpolationPasses = ptr->interpolationPasses;
JSValue ret = JS_NewInt32(ctx, interpolationPasses);
return ret;
}
static JSValue js_LightmapperConfig_set_interpolationPasses(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
int value;
JS_ToInt32(ctx, &value, v);
ptr->interpolationPasses = value;
return JS_UNDEFINED;
}
static JSValue js_LightmapperConfig_get_interpolationThreshold(JSContext* ctx, JSValueConst this_val) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
float interpolationThreshold = ptr->interpolationThreshold;
JSValue ret = JS_NewFloat64(ctx, interpolationThreshold);
return ret;
}
static JSValue js_LightmapperConfig_set_interpolationThreshold(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
double _double_value;
JS_ToFloat64(ctx, &_double_value, v);
float value = (float)_double_value;
ptr->interpolationThreshold = value;
return JS_UNDEFINED;
}
static JSValue js_LightmapperConfig_get_cameraToSurfaceDistanceModifier(JSContext* ctx, JSValueConst this_val) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
float cameraToSurfaceDistanceModifier = ptr->cameraToSurfaceDistanceModifier;
JSValue ret = JS_NewFloat64(ctx, cameraToSurfaceDistanceModifier);
return ret;
}
static JSValue js_LightmapperConfig_set_cameraToSurfaceDistanceModifier(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
LightmapperConfig* ptr = JS_GetOpaque2(ctx, this_val, js_LightmapperConfig_class_id);
double _double_value;
JS_ToFloat64(ctx, &_double_value, v);
float value = (float)_double_value;
ptr->cameraToSurfaceDistanceModifier = value;
return JS_UNDEFINED;
}
static const JSCFunctionListEntry js_LightmapperConfig_proto_funcs[] = {
JS_CGETSET_DEF("hemisphereSize",js_LightmapperConfig_get_hemisphereSize,js_LightmapperConfig_set_hemisphereSize),
JS_CGETSET_DEF("zNear",js_LightmapperConfig_get_zNear,js_LightmapperConfig_set_zNear),
JS_CGETSET_DEF("zFar",js_LightmapperConfig_get_zFar,js_LightmapperConfig_set_zFar),
JS_CGETSET_DEF("backgroundColor",js_LightmapperConfig_get_backgroundColor,js_LightmapperConfig_set_backgroundColor),
JS_CGETSET_DEF("interpolationPasses",js_LightmapperConfig_get_interpolationPasses,js_LightmapperConfig_set_interpolationPasses),
JS_CGETSET_DEF("interpolationThreshold",js_LightmapperConfig_get_interpolationThreshold,js_LightmapperConfig_set_interpolationThreshold),
JS_CGETSET_DEF("cameraToSurfaceDistanceModifier",js_LightmapperConfig_get_cameraToSurfaceDistanceModifier,js_LightmapperConfig_set_cameraToSurfaceDistanceModifier),
JS_PROP_STRING_DEF("[Symbol.toStringTag]","LightmapperConfig", JS_PROP_CONFIGURABLE),
};
static int js_declare_LightmapperConfig(JSContext * ctx, JSModuleDef * m) {
JS_NewClassID(&js_LightmapperConfig_class_id);
JSClassDef js_LightmapperConfig_def = { .class_name = "LightmapperConfig", .finalizer = js_LightmapperConfig_finalizer };
JS_NewClass(JS_GetRuntime(ctx), js_LightmapperConfig_class_id, &js_LightmapperConfig_def);
JSValue proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, proto, js_LightmapperConfig_proto_funcs, countof(js_LightmapperConfig_proto_funcs));
JS_SetClassProto(ctx, js_LightmapperConfig_class_id, proto);
return 0;
}
static JSValue js_Vector2_constructor(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
double _double_x;
JS_ToFloat64(ctx, &_double_x, argv[0]);
@ -10057,6 +10247,94 @@ static JSValue js_easeElasticIn(JSContext * ctx, JSValueConst this_val, int argc
return ret;
}
static JSValue js_getDefaultLightmapperConfig(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
LightmapperConfig returnVal = GetDefaultLightmapperConfig();
LightmapperConfig* ret_ptr = (LightmapperConfig*)js_malloc(ctx, sizeof(LightmapperConfig));
*ret_ptr = returnVal;
JSValue ret = JS_NewObjectClass(ctx, js_LightmapperConfig_class_id);
JS_SetOpaque(ret, ret_ptr);
return ret;
}
static JSValue js_loadLightmapper(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
int w;
JS_ToInt32(ctx, &w, argv[0]);
int h;
JS_ToInt32(ctx, &h, argv[1]);
Mesh* mesh_ptr = (Mesh*)JS_GetOpaque2(ctx, argv[2], js_Mesh_class_id);
if(mesh_ptr == NULL) return JS_EXCEPTION;
Mesh mesh = *mesh_ptr;
LightmapperConfig* cfg_ptr = (LightmapperConfig*)JS_GetOpaque2(ctx, argv[3], js_LightmapperConfig_class_id);
if(cfg_ptr == NULL) return JS_EXCEPTION;
LightmapperConfig cfg = *cfg_ptr;
Lightmapper returnVal = LoadLightmapper(w, h, mesh, cfg);
Lightmapper* ret_ptr = (Lightmapper*)js_malloc(ctx, sizeof(Lightmapper));
*ret_ptr = returnVal;
JSValue ret = JS_NewObjectClass(ctx, js_Lightmapper_class_id);
JS_SetOpaque(ret, ret_ptr);
return ret;
}
static JSValue js_loadMaterialLightmapper(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
Color* emissiveColor_ptr = (Color*)JS_GetOpaque2(ctx, argv[0], js_Color_class_id);
if(emissiveColor_ptr == NULL) return JS_EXCEPTION;
Color emissiveColor = *emissiveColor_ptr;
double _double_intensity;
JS_ToFloat64(ctx, &_double_intensity, argv[1]);
float intensity = (float)_double_intensity;
Material returnVal = LoadMaterialLightmapper(emissiveColor, intensity);
Material* ret_ptr = (Material*)js_malloc(ctx, sizeof(Material));
*ret_ptr = returnVal;
JSValue ret = JS_NewObjectClass(ctx, js_Material_class_id);
JS_SetOpaque(ret, ret_ptr);
return ret;
}
static JSValue js_unloadLightmapper(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
Lightmapper* lm_ptr = (Lightmapper*)JS_GetOpaque2(ctx, argv[0], js_Lightmapper_class_id);
if(lm_ptr == NULL) return JS_EXCEPTION;
Lightmapper lm = *lm_ptr;
UnloadLightmapper(lm);
return JS_UNDEFINED;
}
static JSValue js_beginLightmap(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
BeginLightmap();
return JS_UNDEFINED;
}
static JSValue js_endLightmap(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
EndLightmap();
return JS_UNDEFINED;
}
static JSValue js_beginLightmapFragment(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
Lightmapper* lm = (Lightmapper*)JS_GetOpaque2(ctx, argv[0], js_Lightmapper_class_id);
if(lm == NULL) return JS_EXCEPTION;
bool returnVal = BeginLightmapFragment(lm);
JSValue ret = JS_NewBool(ctx, returnVal);
return ret;
}
static JSValue js_endLightmapFragment(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
Lightmapper* lm = (Lightmapper*)JS_GetOpaque2(ctx, argv[0], js_Lightmapper_class_id);
if(lm == NULL) return JS_EXCEPTION;
EndLightmapFragment(lm);
return JS_UNDEFINED;
}
static JSValue js_loadImageFromLightmapper(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
Lightmapper* lm_ptr = (Lightmapper*)JS_GetOpaque2(ctx, argv[0], js_Lightmapper_class_id);
if(lm_ptr == NULL) return JS_EXCEPTION;
Lightmapper lm = *lm_ptr;
Image returnVal = LoadImageFromLightmapper(lm);
Image* ret_ptr = (Image*)js_malloc(ctx, sizeof(Image));
*ret_ptr = returnVal;
JSValue ret = JS_NewObjectClass(ctx, js_Image_class_id);
JS_SetOpaque(ret, ret_ptr);
return ret;
}
static JSValue js_setModelMaterial(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
Model* model = (Model*)JS_GetOpaque2(ctx, argv[0], js_Model_class_id);
if(model == NULL) return JS_EXCEPTION;
@ -10095,6 +10373,19 @@ static JSValue js_imageReadPixel(JSContext * ctx, JSValueConst this_val, int arg
return ret;
}
static JSValue js_getModelMesh(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
Model* model = (Model*)JS_GetOpaque2(ctx, argv[0], js_Model_class_id);
if(model == NULL) return JS_EXCEPTION;
int meshIndex;
JS_ToInt32(ctx, &meshIndex, argv[1]);
Mesh returnVal = GetModelMesh(model, meshIndex);
Mesh* ret_ptr = (Mesh*)js_malloc(ctx, sizeof(Mesh));
*ret_ptr = returnVal;
JSValue ret = JS_NewObjectClass(ctx, js_Mesh_class_id);
JS_SetOpaque(ret, ret_ptr);
return ret;
}
static const JSCFunctionListEntry js_raylib_core_funcs[] = {
JS_CFUNC_DEF("initWindow",3,js_initWindow),
JS_CFUNC_DEF("windowShouldClose",0,js_windowShouldClose),
@ -10711,9 +11002,19 @@ static const JSCFunctionListEntry js_raylib_core_funcs[] = {
JS_CFUNC_DEF("easeBounceOut",4,js_easeBounceOut),
JS_CFUNC_DEF("easeBounceInOut",4,js_easeBounceInOut),
JS_CFUNC_DEF("easeElasticIn",4,js_easeElasticIn),
JS_CFUNC_DEF("getDefaultLightmapperConfig",0,js_getDefaultLightmapperConfig),
JS_CFUNC_DEF("loadLightmapper",4,js_loadLightmapper),
JS_CFUNC_DEF("loadMaterialLightmapper",2,js_loadMaterialLightmapper),
JS_CFUNC_DEF("unloadLightmapper",1,js_unloadLightmapper),
JS_CFUNC_DEF("beginLightmap",0,js_beginLightmap),
JS_CFUNC_DEF("endLightmap",0,js_endLightmap),
JS_CFUNC_DEF("beginLightmapFragment",1,js_beginLightmapFragment),
JS_CFUNC_DEF("endLightmapFragment",1,js_endLightmapFragment),
JS_CFUNC_DEF("loadImageFromLightmapper",1,js_loadImageFromLightmapper),
JS_CFUNC_DEF("setModelMaterial",3,js_setModelMaterial),
JS_CFUNC_DEF("setShaderLocation",3,js_setShaderLocation),
JS_CFUNC_DEF("imageReadPixel",3,js_imageReadPixel),
JS_CFUNC_DEF("getModelMesh",2,js_getModelMesh),
};
static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) {
@ -10777,6 +11078,8 @@ static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) {
js_declare_VrStereoConfig(ctx, m);
js_declare_FilePathList(ctx, m);
js_declare_Light(ctx, m);
js_declare_Lightmapper(ctx, m);
js_declare_LightmapperConfig(ctx, m);
Color LIGHTGRAY_struct = { 200, 200, 200, 255 };
Color* LIGHTGRAY_js_ptr = (Color*)js_malloc(ctx, sizeof(Color));
*LIGHTGRAY_js_ptr = LIGHTGRAY_struct;

View File

@ -1,118 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include <raylib.h>
#include <rlgl.h>
#include <raymath.h>
#include <external/glad.h>
#define RLIGHTMAPPER_IMPLEMENTATION
#include "rlightmapper.h"
typedef struct
{
//Shader raylib_shader;
Texture raylib_texture;
int w, h;
Model raylib_model;
Model model2;
Camera camera;
Shader shader;
GLuint u_intensity;
} scene_t;
static void drawScene(scene_t *scene){
DrawModel(scene->raylib_model, (Vector3){ 0,0,0 }, 1, WHITE);
//DrawModel(scene->model2, (Vector3){ -10,10,0.0 }, 3,RAYWHITE);
}
int main(int argc, char* argv[])
{
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI | FLAG_VSYNC_HINT);
InitWindow(1024,768,"Test");
scene_t scene = {0};
scene.shader = LoadShader("assets/shaders/glsl330/default.vs","assets/shaders/glsl330/default.fs");
scene.u_intensity = GetShaderLocation(scene.shader, "intensity");
// load mesh
scene.raylib_model = LoadModel("monkey.obj");
scene.raylib_model.materials[0].shader = scene.shader;
scene.model2 = LoadModel("thirdparty/lightmapper/example/cube.obj");
scene.model2.materials[0].shader = scene.shader;
scene.w = 512;
scene.h = 512;
scene.raylib_texture = LoadTextureFromImage(GenImageColor(1,1,BLACK));
scene.raylib_model.materials[0].maps[0].texture = scene.raylib_texture;
Camera camera = { 0 };
camera.position = (Vector3){ 0.0f, 0.5f, 1.5f }; // Camera position
camera.target = (Vector3){ 0.0f, 0.35f, 0.0f }; // Camera looking at point
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
camera.fovy = 45.0f; // Camera field-of-view Y
camera.projection = CAMERA_PERSPECTIVE; // Camera mode type
scene.camera = camera;
LightmapperConfig config = GetDefaultLightmapperConfig();
config.backgroundColor = (Color){6,0,10};
//config.hemisphereSize = 512;
Lightmapper lm = LoadLightmapper(scene.w, scene.h, scene.raylib_model.meshes[0], config);
Material lmMat = LoadMaterialLightmapper(BLACK, 0);
Mesh light = GenMeshCube(0.3,0.3, 0.3);
Material lightMaterial = LoadMaterialLightmapper(ORANGE, 1.0f);
while (!WindowShouldClose())
{
if(IsMouseButtonDown(MOUSE_BUTTON_LEFT))
UpdateCamera(&scene.camera, CAMERA_THIRD_PERSON);
if(lm.progress < 1.0f){
double startTime = GetTime();
BeginLightmap();
while(BeginLightmapFragment(&lm)){
DrawMesh(scene.raylib_model.meshes[0], lmMat, MatrixIdentity());
DrawMesh(light, lightMaterial, MatrixTranslate(0,1.0,0));
EndLightmapFragment(&lm);
// display progress every second (printf is expensive)
double time = GetTime();
if (GetTime() - startTime > 0.03) break;
}
EndLightmap();
if(lm.progress == 1.0f){
Image img = LoadImageFromLightmapper(lm);
//ExportImage(img, "my_result.png");
UnloadTexture(scene.raylib_texture);
scene.raylib_texture = LoadTextureFromImage(img);
scene.raylib_model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = scene.raylib_texture;
UnloadLightmapper(lm);
}
}
BeginDrawing();
ClearBackground(BLUE);
BeginMode3D(scene.camera);
float intensity = 1.0f;
SetShaderValue(scene.shader, scene.u_intensity, &intensity, SHADER_UNIFORM_FLOAT);
drawScene(&scene);
EndMode3D();
// printf("%d\n",(int)(lm.progress*GetScreenWidth()));
if(lm.progress < 1.0f){
DrawRectangle(0,0,GetScreenWidth(),20, Fade(GREEN,0.5));
DrawRectangle(0,0,GetScreenWidth()*lm.progress,20, GREEN);
}
EndDrawing();
}
UnloadModel(scene.raylib_model);
UnloadTexture(scene.raylib_texture);
CloseWindow();
return EXIT_SUCCESS;
}

View File

@ -1,192 +0,0 @@
#include <stdlib.h>
#include "raylib.h"
#include "rlgl.h"
#define GLAD_MALLOC(sz) malloc(sz)
#define GLAD_FREE(sz) free(sz)
//#define GLAD_GL_IMPLEMENTATION
#include "../thirdparty/raylib/src/external/glad.h"
#define LIGHTMAPPER_IMPLEMENTATION
#define LM_DEBUG_INTERPOLATION
#include "lightmapper.h"
// load shader
const char *vp =
"#version 150 core\n"
"in vec3 a_position;\n"
"in vec2 a_texcoord;\n"
"uniform mat4 u_view;\n"
"uniform mat4 u_projection;\n"
"out vec2 v_texcoord;\n"
"void main()\n"
"{\n"
"gl_Position = u_projection * (u_view * vec4(a_position, 1.0));\n"
"v_texcoord = a_texcoord;\n"
"}\n";
const char *fp =
"#version 150 core\n"
"in vec2 v_texcoord;\n"
"uniform sampler2D u_lightmap;\n"
"out vec4 o_color;\n"
"void main()\n"
"{\n"
"o_color = vec4(texture(u_lightmap, v_texcoord).rgb, gl_FrontFacing ? 1.0 : 0.0);\n"
"}\n";
const char *attribs[] =
{
"a_position",
"a_texcoord"
};
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [models] lightmapping");
Model model = LoadModel("thirdparty/lightmapper/example/gazebo.obj");
Shader shader = LoadShaderFromMemory(vp, fp);
Texture texture = LoadTextureFromImage(GenImageColor(1,1,BLACK));
int u_view = GetShaderLocation(shader, "u_view");
int u_projection = GetShaderLocation(shader, "u_projection");
int u_lightmap = GetShaderLocation(shader, "u_lightmap");
Vector3 position = { 0.0f, 0.0f, 0.0f };
//--------------------------------------------------------------------------------------
lm_context *ctx = lmCreate(
64, // hemisphere resolution (power of two, max=512)
0.001f, 100.0f, // zNear, zFar of hemisphere cameras
1.0f, 1.0f, 1.0f, // background color (white for ambient occlusion)
2, 0.01f, // lightmap interpolation threshold (small differences are interpolated rather than sampled)
// check debug_interpolation.tga for an overview of sampled (red) vs interpolated (green) pixels.
0.0f); // modifier for camera-to-surface distance for hemisphere rendering.
// tweak this to trade-off between interpolated normals quality and other artifacts (see declaration).
if (!ctx) TraceLog(LOG_ERROR, "Lightmapper not initialized");
int w = 512;
int h = 512;
float *data = calloc(w*h*4,sizeof(float));
lmSetTargetLightmap(ctx, data, w, h, 4);
Mesh m = model.meshes[0];
lmSetGeometry(ctx, NULL, // no transformation in this example
LM_FLOAT, m.vertices, 0,
LM_NONE , NULL, 0,
LM_FLOAT, m.texcoords, 0,
m.vertexCount, LM_NONE, 0);
printf("%p\n", m.texcoords);
int vp[4];
Matrix view, projection;
double lastUpdateTime = 0.0;
Mesh mesh = model.meshes[0];
//SetTargetFPS(10000);
while (lmBegin(ctx, vp, (float*)&view, (float*)&projection))
{
glViewport(vp[0], vp[1], vp[2], vp[3]);
glEnable(GL_DEPTH_TEST);
glUseProgram(shader.id);
glUniform1i(u_lightmap, 0);
glUniformMatrix4fv(u_projection, 1, GL_FALSE, (float *)&projection);
glUniformMatrix4fv(u_view, 1, GL_FALSE, (float *)&view);
glBindTexture(GL_TEXTURE_2D, texture.id);
glBindVertexArray(mesh.vaoId);
glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
double time = GetTime();
if (time - lastUpdateTime > 1.0)
{
lastUpdateTime = time;
printf("\r%6.2f%%", lmProgress(ctx) * 100.0f);
fflush(stdout);
}
lmEnd(ctx);
if(WindowShouldClose()) break;
}
// postprocess texture
float *temp = calloc(w * h * 4, sizeof(float));
for (int i = 0; i < 16; i++)
{
lmImageDilate(data, temp, w, h, 4);
lmImageDilate(temp, data, w, h, 4);
}
lmImageSmooth(data, temp, w, h, 4);
lmImageDilate(temp, data, w, h, 4);
lmImagePower(data, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels
free(temp);
// save result to a file
if (lmImageSaveTGAf("result.tga", data, w, h, 4, 1.0f))
printf("Saved result.tga\n");
rlViewport(0,0, screenWidth, screenHeight);
// Define the camera to look into our 3d world
Camera camera = { 0 };
camera.position = (Vector3){ 1.0f, 0.5f, 1.0f }; // Camera position
camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
camera.fovy = 45.0f; // Camera field-of-view Y
camera.projection = CAMERA_PERSPECTIVE; // Camera mode type
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
//UpdateCamera(&camera, CAMERA_FIRST_PERSON);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
DrawModel(model, position, 1.0f, WHITE);
EndMode3D();
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
//UnloadTexture(texture); // Unload texture
UnloadModel(model); // Unload model
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -4,6 +4,7 @@
#include <errno.h>
#include <quickjs.h>
//#include <quickjs-libc.h>
#include <external/glad.h>
#include <GLFW/glfw3.h>
#include <raylib.h>
@ -212,6 +213,12 @@ void SetModelMaterial(Model *model, int materialIndex, Material material)
model->materials[materialIndex] = material;
}
Mesh GetModelMesh(Model *model, int meshIndex){
Mesh m = { 0 };
if(model->meshCount <= meshIndex) return m;
return model->meshes[meshIndex];
}
void SetShaderLocation(Shader *shader, int constant, int location){
shader->locs[constant] = location;
}

View File

@ -1,233 +1,267 @@
#ifndef RLIGHTMAPPER_H
#define RLIGHTMAPPER_H
#include <raylib.h>
typedef struct Lightmapper {
void * lm_handle;
float * data;
int w;
int h;
float progress;
} Lightmapper;
typedef struct LightmapperConfig {
int hemisphereSize;
float zNear;
float zFar;
Color backgroundColor;
int interpolationPasses;
float interpolationThreshold;
float cameraToSurfaceDistanceModifier;
} LightmapperConfig;
LightmapperConfig GetDefaultLightmapperConfig();
Lightmapper LoadLightmapper(int w, int h, Mesh mesh, LightmapperConfig cfg);
Material LoadMaterialLightmapper(Color emissiveColor, float intensity);
void UnloadLightmapper(Lightmapper lm);
void BeginLightmap();
void EndLightmap();
bool BeginLightmapFragment(Lightmapper * lm);
void EndLightmapFragment(Lightmapper * lm);
Image LoadImageFromLightmapper(Lightmapper lm);
#endif
#if defined(RLIGHTMAPPER_IMPLEMENTATION)
#define LIGHTMAPPER_IMPLEMENTATION
//#define LM_DEBUG_INTERPOLATION
#include "lightmapper.h"
static const char* fs =
"#version 330\n"
"in vec2 fragTexCoord;\n"
"in vec4 fragColor;\n"
"out vec4 finalColor;\n"
"uniform sampler2D texture0;\n"
"uniform vec4 colDiffuse;\n"
"void main()\n"
"{\n"
" vec4 texelColor = texture(texture0, fragTexCoord);\n"
" texelColor = texelColor * colDiffuse * fragColor * vec4(intensity, intensity, intensity, 1.0);\n"
" finalColor = vec4(texelColor.rgb, (gl_FrontFacing ? 1.0 : 0.0));\n"
"}";
const char* vs = "#version 330\n"
"in vec3 vertexPosition;\n"
"in vec2 vertexTexCoord;\n"
"in vec4 vertexColor;\n"
"out vec2 fragTexCoord;\n"
"out vec4 fragColor;\n"
"uniform mat4 mvp;\n"
"void main()\n"
"{\n"
" fragTexCoord = vertexTexCoord;\n"
" fragColor = vertexColor;\n"
" gl_Position = mvp * vec4(vertexPosition, 1.0);\n"
"}";
static void FloatVToMatrix(float *array, struct Matrix *matrix) {
matrix->m0 = array[0];
matrix->m1 = array[1];
matrix->m2 = array[2];
matrix->m3 = array[3];
matrix->m4 = array[4];
matrix->m5 = array[5];
matrix->m6 = array[6];
matrix->m7 = array[7];
matrix->m8 = array[8];
matrix->m9 = array[9];
matrix->m10 = array[10];
matrix->m11 = array[11];
matrix->m12 = array[12];
matrix->m13 = array[13];
matrix->m14 = array[14];
matrix->m15 = array[15];
}
LightmapperConfig GetDefaultLightmapperConfig(){
return (LightmapperConfig){
64, 0.001f, 100.0f, WHITE, 2, 0.01f, 0.0f
};
}
static Shader defaultShader;
Material LoadMaterialLightmapper(Color emissiveColor, float emissiveIntensity)
{
if(defaultShader.id == 0) defaultShader = LoadShaderFromMemory(vs, fs);
Material mat = LoadMaterialDefault();
mat.shader = defaultShader;
mat.maps[MATERIAL_MAP_DIFFUSE].color = emissiveColor; // Diffuse color
//mat.params[0] = emissiveIntensity;
return mat;
}
Lightmapper LoadLightmapper(int w, int h, Mesh mesh, LightmapperConfig cfg){
Lightmapper lm = {0};
lm_context* ctx = lm.lm_handle = lmCreate(cfg.hemisphereSize, cfg.zNear, cfg.zFar,
cfg.backgroundColor.r / (float)255, cfg.backgroundColor.g / (float)255, cfg.backgroundColor.b / (float)255,
cfg.interpolationPasses, cfg.interpolationThreshold, cfg.cameraToSurfaceDistanceModifier);
if(ctx == NULL){
TraceLog(LOG_ERROR, "Unable to create lightmapper. Init failed.");
goto RETURN;
}
lm.w = w;
lm.h = h;
float *data = lm.data = calloc(w * h * 4, sizeof(float));
lmSetTargetLightmap(ctx, data, w, h, 4);
const void* indices = NULL;
lm_type indicesType = LM_NONE;
int count = mesh.vertexCount;
if(mesh.indices != NULL){
indices = mesh.indices;
indicesType = LM_UNSIGNED_SHORT;
count = mesh.triangleCount * 3;
}
lmSetGeometry(ctx, NULL,
LM_FLOAT, (unsigned char*)mesh.vertices, 0,
LM_FLOAT , (unsigned char*)mesh.normals, 0,
LM_FLOAT, (unsigned char*)mesh.texcoords, 0,
count, indicesType, indices);
RETURN:
return lm;
}
void UnloadLightmapper(Lightmapper lm){
free(lm.data);
lmDestroy((lm_context *)lm.lm_handle);
}
static Matrix mProjection;
static Matrix mModelview;
void BeginLightmap()
{
rlEnableDepthTest();
rlDisableColorBlend();
rlDisableBackfaceCulling();
mProjection = rlGetMatrixProjection();
mModelview = rlGetMatrixModelview();
}
void EndLightmap(){
//rlDisableDepthTest();
rlEnableColorBlend();
rlEnableBackfaceCulling();
int w = GetScreenWidth() * GetWindowScaleDPI().x;
int h = GetScreenHeight() * GetWindowScaleDPI().y;
rlViewport(0, 0, w, h);
rlDisableFramebuffer();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
rlSetMatrixModelview(mModelview);
rlSetMatrixProjection(mProjection);
}
static int vp[4];
static float view[16], projection[16];
static Matrix matView, matProj;
bool BeginLightmapFragment(Lightmapper * lm){
lm_bool status = lmBegin((lm_context *)lm->lm_handle, vp, view, projection);
if(status){
rlViewport(vp[0], vp[1], vp[2], vp[3]);
FloatVToMatrix(view, &matView);
FloatVToMatrix(projection, &matProj);
rlSetMatrixModelview(matView);
rlSetMatrixProjection(matProj);
} else {
lm->progress = 1.0f;
}
return (bool)status;
}
void EndLightmapFragment(Lightmapper * lm){
lm->progress = lmProgress((lm_context *)lm->lm_handle);
lmEnd((lm_context *)lm->lm_handle);
}
Image LoadImageFromLightmapper(Lightmapper lm){
Image im = { 0 };
if(lm.progress < 1.0f){
TraceLog(LOG_ERROR, "Lightmapping is not finished");
return im;
}
// postprocess texture
float *temp = calloc(lm.w * lm.h * 4, sizeof(float));
for (int i = 0; i < 16; i++)
{
lmImageDilate(lm.data, temp, lm.w, lm.h, 4);
lmImageDilate(temp, lm.data, lm.w, lm.h, 4);
}
lmImageSmooth(lm.data, temp, lm.w, lm.h, 4);
lmImageDilate(temp, lm.data, lm.w, lm.h, 4);
lmImagePower(lm.data, lm.w, lm.h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels
free(temp);
unsigned char *tempub = (unsigned char*)calloc(lm.w * lm.h * 4, sizeof(unsigned char));
lmImageFtoUB(lm.data, tempub, lm.w, lm.h, 4, 1.0f);
im.data = tempub;
im.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
im.height = lm.w;
im.width = lm.h;
im.mipmaps = 1;
return im;
}
#ifndef RLIGHTMAPPER_H
#define RLIGHTMAPPER_H
// ...
typedef struct {
void *lm_handle;
float *data;
int w;
int h;
float progress;
} Lightmapper;
// ...
typedef struct {
int hemisphereSize;
float zNear;
float zFar;
Color backgroundColor;
int interpolationPasses;
float interpolationThreshold;
float cameraToSurfaceDistanceModifier;
} LightmapperConfig;
#define RLMAPI
// ...
RLMAPI LightmapperConfig GetDefaultLightmapperConfig(void);
// ...
RLMAPI Lightmapper LoadLightmapper(int w, int h, Mesh mesh, LightmapperConfig cfg);
// ...
RLMAPI Material LoadMaterialLightmapper(Color emissiveColor, float intensity);
// ...
RLMAPI void UnloadLightmapper(Lightmapper lm);
// ...
RLMAPI void BeginLightmap(void);
// ...
RLMAPI void EndLightmap(void);
// ..
RLMAPI bool BeginLightmapFragment(Lightmapper *lm);
// ...
RLMAPI void EndLightmapFragment(Lightmapper *lm);
// ...
RLMAPI Image LoadImageFromLightmapper(Lightmapper lm);
#endif
#if defined(RLIGHTMAPPER_IMPLEMENTATION)
#include <rlgl.h>
#define LIGHTMAPPER_IMPLEMENTATION
// #define LM_DEBUG_INTERPOLATION
#include "lightmapper.h"
static const char *fs =
"#version 330\n"
"in vec2 fragTexCoord;\n"
"in vec4 fragColor;\n"
"out vec4 finalColor;\n"
"uniform sampler2D texture0;\n"
"uniform sampler2D texture1;\n"
"uniform vec4 colDiffuse;\n"
"void main()\n"
"{\n"
" vec4 texelColor = texture(texture0, fragTexCoord);\n"
" vec4 emissionColor = texture(texture1, fragTexCoord);\n"
" texelColor = texelColor * colDiffuse * fragColor * emissionColor;\n"
" finalColor = vec4(texelColor.rgb, (gl_FrontFacing ? 1.0 : 0.0));\n"
"}";
const char *vs = "#version 330\n"
"in vec3 vertexPosition;\n"
"in vec2 vertexTexCoord;\n"
"in vec4 vertexColor;\n"
"out vec2 fragTexCoord;\n"
"out vec4 fragColor;\n"
"uniform mat4 mvp;\n"
"void main()\n"
"{\n"
" fragTexCoord = vertexTexCoord;\n"
" fragColor = vertexColor;\n"
" gl_Position = mvp * vec4(vertexPosition, 1.0);\n"
"}";
static void FloatVToMatrix(float *array, struct Matrix *matrix)
{
matrix->m0 = array[0];
matrix->m1 = array[1];
matrix->m2 = array[2];
matrix->m3 = array[3];
matrix->m4 = array[4];
matrix->m5 = array[5];
matrix->m6 = array[6];
matrix->m7 = array[7];
matrix->m8 = array[8];
matrix->m9 = array[9];
matrix->m10 = array[10];
matrix->m11 = array[11];
matrix->m12 = array[12];
matrix->m13 = array[13];
matrix->m14 = array[14];
matrix->m15 = array[15];
}
LightmapperConfig GetDefaultLightmapperConfig()
{
return (LightmapperConfig){
64, 0.001f, 100.0f, WHITE, 2, 0.01f, 0.0f};
}
static Shader defaultShader;
Material LoadMaterialLightmapper(Color emissiveColor, float emissiveIntensity)
{
if (defaultShader.id == 0)
defaultShader = LoadShaderFromMemory(vs, fs);
Material mat = LoadMaterialDefault();
mat.shader = defaultShader;
float colF[4] = {emissiveColor.r * emissiveIntensity, emissiveColor.g * emissiveIntensity, emissiveColor.b * emissiveIntensity, emissiveColor.a * emissiveIntensity};
Texture tex = {0};
tex.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32A32;
tex.width = 1;
tex.height = 1;
tex.mipmaps = 1;
tex.id = rlLoadTexture(colF, 1, 1, RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, 1);
mat.maps[MATERIAL_MAP_SPECULAR].texture = tex;
// mat.params[0] = emissiveIntensity;
return mat;
}
Lightmapper LoadLightmapper(int w, int h, Mesh mesh, LightmapperConfig cfg)
{
Lightmapper lm = {0};
lm_context *ctx = lm.lm_handle = lmCreate(cfg.hemisphereSize, cfg.zNear, cfg.zFar,
cfg.backgroundColor.r / (float)255, cfg.backgroundColor.g / (float)255, cfg.backgroundColor.b / (float)255,
cfg.interpolationPasses, cfg.interpolationThreshold, cfg.cameraToSurfaceDistanceModifier);
if (ctx == NULL)
{
TraceLog(LOG_ERROR, "Unable to create lightmapper. Init failed.");
goto RETURN;
}
lm.w = w;
lm.h = h;
float *data = lm.data = calloc(w * h * 4, sizeof(float));
lmSetTargetLightmap(ctx, data, w, h, 4);
const void *indices = NULL;
lm_type indicesType = LM_NONE;
int count = mesh.vertexCount;
if (mesh.indices != NULL)
{
indices = mesh.indices;
indicesType = LM_UNSIGNED_SHORT;
count = mesh.triangleCount * 3;
}
lmSetGeometry(ctx, NULL,
LM_FLOAT, (unsigned char *)mesh.vertices, 0,
LM_FLOAT, (unsigned char *)mesh.normals, 0,
LM_FLOAT, (unsigned char *)mesh.texcoords, 0,
count, indicesType, indices);
RETURN:
return lm;
}
void UnloadLightmapper(Lightmapper lm)
{
free(lm.data);
lmDestroy((lm_context *)lm.lm_handle);
}
static Matrix mProjection;
static Matrix mModelview;
void BeginLightmap()
{
rlEnableDepthTest();
rlDisableColorBlend();
rlDisableBackfaceCulling();
mProjection = rlGetMatrixProjection();
mModelview = rlGetMatrixModelview();
}
void EndLightmap()
{
// rlDisableDepthTest();
rlEnableColorBlend();
rlEnableBackfaceCulling();
int w = GetScreenWidth() * GetWindowScaleDPI().x;
int h = GetScreenHeight() * GetWindowScaleDPI().y;
rlViewport(0, 0, w, h);
rlDisableFramebuffer();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
rlSetMatrixModelview(mModelview);
rlSetMatrixProjection(mProjection);
}
static int vp[4];
static float view[16], projection[16];
static Matrix matView, matProj;
bool BeginLightmapFragment(Lightmapper *lm)
{
lm_bool status = lmBegin((lm_context *)lm->lm_handle, vp, view, projection);
if (status)
{
rlViewport(vp[0], vp[1], vp[2], vp[3]);
FloatVToMatrix(view, &matView);
FloatVToMatrix(projection, &matProj);
rlSetMatrixModelview(matView);
rlSetMatrixProjection(matProj);
}
else
{
lm->progress = 1.0f;
}
return (bool)status;
}
void EndLightmapFragment(Lightmapper *lm)
{
lm->progress = lmProgress((lm_context *)lm->lm_handle);
lmEnd((lm_context *)lm->lm_handle);
}
Image LoadImageFromLightmapper(Lightmapper lm)
{
Image im = {0};
if (lm.progress < 1.0f)
{
TraceLog(LOG_ERROR, "Lightmapping is not finished");
return im;
}
// postprocess texture
float *temp = calloc(lm.w * lm.h * 4, sizeof(float));
for (int i = 0; i < 16; i++)
{
lmImageDilate(lm.data, temp, lm.w, lm.h, 4);
lmImageDilate(temp, lm.data, lm.w, lm.h, 4);
}
lmImageSmooth(lm.data, temp, lm.w, lm.h, 4);
lmImageDilate(temp, lm.data, lm.w, lm.h, 4);
lmImagePower(lm.data, lm.w, lm.h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels
free(temp);
unsigned char *tempub = (unsigned char *)calloc(lm.w * lm.h * 4, sizeof(unsigned char));
lmImageFtoUB(lm.data, tempub, lm.w, lm.h, 4, 1.0f);
im.data = tempub;
im.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
im.height = lm.w;
im.width = lm.h;
im.mipmaps = 1;
return im;
}
#endif