Add color support.
This commit is contained in:
@@ -2,15 +2,20 @@ module('spritebatch')
|
|||||||
module('time')
|
module('time')
|
||||||
module('camera')
|
module('camera')
|
||||||
module('glm')
|
module('glm')
|
||||||
|
module('color')
|
||||||
|
|
||||||
camera = cameraCreate(CAMERA_PROJECTION_TYPE_PERSPECTIVE)
|
camera = cameraCreate(CAMERA_PROJECTION_TYPE_PERSPECTIVE)
|
||||||
|
|
||||||
|
color = colorBlue()
|
||||||
|
|
||||||
function sceneDispose()
|
function sceneDispose()
|
||||||
-- print('Disposing initial scene')
|
-- print('Disposing initial scene')
|
||||||
end
|
end
|
||||||
|
|
||||||
function sceneUpdate()
|
function sceneUpdate()
|
||||||
-- print('Updating initial scene')
|
color.r = 255 * (math.sin(TIME.time) + 1) * 0.5
|
||||||
|
color.g = 255 * (math.sin(TIME.time + 2) + 1) * 0.5
|
||||||
|
color.b = 255 * (math.sin(TIME.time + 4) + 1) * 0.5
|
||||||
end
|
end
|
||||||
|
|
||||||
function sceneRender()
|
function sceneRender()
|
||||||
@@ -19,8 +24,8 @@ function sceneRender()
|
|||||||
spriteBatchPush(
|
spriteBatchPush(
|
||||||
nil,
|
nil,
|
||||||
0, 0,
|
0, 0,
|
||||||
1, 1,
|
1, 2,
|
||||||
nil
|
color
|
||||||
)
|
)
|
||||||
spriteBatchFlush()
|
spriteBatchFlush()
|
||||||
|
|
||||||
|
|||||||
@@ -38,3 +38,11 @@ elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
|||||||
DISPLAY_SIZE_DYNAMIC=0
|
DISPLAY_SIZE_DYNAMIC=0
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
dusk_run_python(
|
||||||
|
dusk_color_defs
|
||||||
|
tools.display.color.csv
|
||||||
|
--csv ${CMAKE_CURRENT_SOURCE_DIR}/color.csv
|
||||||
|
--output ${DUSK_GENERATED_HEADERS_DIR}/display/color.h
|
||||||
|
)
|
||||||
|
add_dependencies(${DUSK_LIBRARY_TARGET_NAME} dusk_color_defs)
|
||||||
@@ -20,3 +20,4 @@ pink,1,0.75,0.8,1
|
|||||||
lime,0.75,1,0,1
|
lime,0.75,1,0,1
|
||||||
navy,0,0,0.5,1
|
navy,0,0,0.5,1
|
||||||
teal,0,0.5,0.5,1
|
teal,0,0.5,0.5,1
|
||||||
|
cornflower_blue,0.39,0.58,0.93,1
|
||||||
|
@@ -14,7 +14,45 @@
|
|||||||
void moduleColor(scriptcontext_t *context) {
|
void moduleColor(scriptcontext_t *context) {
|
||||||
assertNotNull(context, "Context cannot be NULL.");
|
assertNotNull(context, "Context cannot be NULL.");
|
||||||
|
|
||||||
scriptStructRegister(context, "color_mt", moduleColorGetter, NULL);
|
scriptStructRegister(
|
||||||
|
context, "color_mt", moduleColorGetter, moduleColorSetter
|
||||||
|
);
|
||||||
|
|
||||||
|
scriptContextRegFunc(context, "color", moduleColorFuncColor);
|
||||||
|
|
||||||
|
scriptContextExec(context, COLOR_SCRIPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int moduleColorFuncColor(lua_State *L) {
|
||||||
|
assertNotNull(L, "Lua state cannot be NULL.");
|
||||||
|
|
||||||
|
scriptcontext_t *context = *(scriptcontext_t **)lua_getextraspace(L);
|
||||||
|
assertNotNull(context, "Script context cannot be NULL.");
|
||||||
|
|
||||||
|
// Needs 4 channel uint8_t
|
||||||
|
if(
|
||||||
|
!lua_isnumber(L, 1) || !lua_isnumber(L, 2) ||
|
||||||
|
!lua_isnumber(L, 3) || !lua_isnumber(L, 4)
|
||||||
|
) {
|
||||||
|
return luaL_error(L, "color(r, g, b, a) requires four number arguments.");
|
||||||
|
}
|
||||||
|
|
||||||
|
colorchannel8_t r = (colorchannel8_t)lua_tonumber(L, 1);
|
||||||
|
colorchannel8_t g = (colorchannel8_t)lua_tonumber(L, 2);
|
||||||
|
colorchannel8_t b = (colorchannel8_t)lua_tonumber(L, 3);
|
||||||
|
colorchannel8_t a = (colorchannel8_t)lua_tonumber(L, 4);
|
||||||
|
|
||||||
|
// Create color_t as lua memory
|
||||||
|
color_t *color = (color_t*)lua_newuserdata(L, sizeof(color_t));
|
||||||
|
color->r = r;
|
||||||
|
color->g = g;
|
||||||
|
color->b = b;
|
||||||
|
color->a = a;
|
||||||
|
|
||||||
|
// Push color struct
|
||||||
|
scriptStructPushMetatable(context, "color_mt", color);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void moduleColorGetter(
|
void moduleColorGetter(
|
||||||
@@ -46,3 +84,50 @@ void moduleColorGetter(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void moduleColorSetter(
|
||||||
|
const scriptcontext_t *context,
|
||||||
|
const char_t *key,
|
||||||
|
void *structPtr,
|
||||||
|
const scriptvalue_t *inValue
|
||||||
|
) {
|
||||||
|
color_t *color = (color_t*)structPtr;
|
||||||
|
|
||||||
|
if(stringCompare(key, "r") == 0) {
|
||||||
|
if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
|
||||||
|
color->r = (colorchannel8_t)inValue->value.intValue;
|
||||||
|
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
|
||||||
|
color->r = (colorchannel8_t)(inValue->value.floatValue);
|
||||||
|
} else {
|
||||||
|
assertUnreachable("Invalid type for color channel r");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if(stringCompare(key, "g") == 0) {
|
||||||
|
if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
|
||||||
|
color->g = (colorchannel8_t)inValue->value.intValue;
|
||||||
|
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
|
||||||
|
color->g = (colorchannel8_t)(inValue->value.floatValue);
|
||||||
|
} else {
|
||||||
|
assertUnreachable("Invalid type for color channel g");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if(stringCompare(key, "b") == 0) {
|
||||||
|
if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
|
||||||
|
color->b = (colorchannel8_t)inValue->value.intValue;
|
||||||
|
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
|
||||||
|
color->b = (colorchannel8_t)(inValue->value.floatValue);
|
||||||
|
} else {
|
||||||
|
assertUnreachable("Invalid type for color channel b");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if(stringCompare(key, "a") == 0) {
|
||||||
|
if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
|
||||||
|
color->a = (colorchannel8_t)inValue->value.intValue;
|
||||||
|
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
|
||||||
|
color->a = (colorchannel8_t)(inValue->value.floatValue);
|
||||||
|
} else {
|
||||||
|
assertUnreachable("Invalid type for color channel a");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
void moduleColor(scriptcontext_t *context);
|
void moduleColor(scriptcontext_t *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lua function to create a color.
|
||||||
|
*
|
||||||
|
* @param L The Lua state.
|
||||||
|
* @return Number of return values.
|
||||||
|
*/
|
||||||
|
int moduleColorFuncColor(lua_State *L);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter function for the color structure.
|
* Getter function for the color structure.
|
||||||
*
|
*
|
||||||
@@ -29,3 +37,18 @@ void moduleColorGetter(
|
|||||||
const void *structPtr,
|
const void *structPtr,
|
||||||
scriptvalue_t *outValue
|
scriptvalue_t *outValue
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter function for the color structure.
|
||||||
|
*
|
||||||
|
* @param context The script context.
|
||||||
|
* @param key The key to set.
|
||||||
|
* @param structPtr Pointer to the color structure.
|
||||||
|
* @param inValue Input value.
|
||||||
|
*/
|
||||||
|
void moduleColorSetter(
|
||||||
|
const scriptcontext_t *context,
|
||||||
|
const char_t *key,
|
||||||
|
void *structPtr,
|
||||||
|
const scriptvalue_t *inValue
|
||||||
|
);
|
||||||
@@ -45,13 +45,17 @@ int moduleSpriteBatchPush(lua_State *L) {
|
|||||||
return luaL_error(L, "Sprite coordinates must be numbers");
|
return luaL_error(L, "Sprite coordinates must be numbers");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color (struct), must be Nil for now
|
// Color (struct) or nil for white
|
||||||
if(!lua_isnil(L, 6)) {
|
color_t *color = NULL;
|
||||||
return luaL_error(L, "Color parameter must be nil");
|
if(lua_isuserdata(L, 6)) {
|
||||||
|
color = *(color_t**)lua_touserdata(L, 6);
|
||||||
|
assertNotNull(color, "Color struct cannot be NULL");
|
||||||
|
} else if(lua_isnil(L, 6)) {
|
||||||
|
// Extrapolate later.
|
||||||
|
} else {
|
||||||
|
return luaL_error(L, "Sprite color must be a color struct or nil");
|
||||||
}
|
}
|
||||||
// if(!lua_istable(L, 6)) {
|
|
||||||
// return luaL_error(L, "Color parameter must be a color struct");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Optional UV min and maxes, defaults to 0,0 -> 1,1
|
// Optional UV min and maxes, defaults to 0,0 -> 1,1
|
||||||
float_t u0 = 0.0f;
|
float_t u0 = 0.0f;
|
||||||
@@ -88,7 +92,7 @@ int moduleSpriteBatchPush(lua_State *L) {
|
|||||||
minY,
|
minY,
|
||||||
maxX,
|
maxX,
|
||||||
maxY,
|
maxY,
|
||||||
COLOR_MAGENTA,
|
color == NULL ? COLOR_WHITE : *color,
|
||||||
u0,
|
u0,
|
||||||
v0,
|
v0,
|
||||||
u1,
|
u1,
|
||||||
|
|||||||
@@ -17,48 +17,88 @@ outHeader += '#include "dusk.h"\n\n'
|
|||||||
|
|
||||||
outHeader += f"typedef float_t colorchannelf_t;\n"
|
outHeader += f"typedef float_t colorchannelf_t;\n"
|
||||||
|
|
||||||
|
colors = {}
|
||||||
|
|
||||||
with open(args.csv, newline="", encoding="utf-8") as csvfile:
|
with open(args.csv, newline="", encoding="utf-8") as csvfile:
|
||||||
reader = csv.DictReader(csvfile)
|
reader = csv.DictReader(csvfile)
|
||||||
|
|
||||||
# CSV must have id column.
|
# CSV must have id column.
|
||||||
if "id" not in reader.fieldnames:
|
if "name" not in reader.fieldnames:
|
||||||
raise Exception("CSV file must have 'id' column")
|
raise Exception("CSV file must have 'name' column")
|
||||||
|
|
||||||
# For each ID
|
# For each color, by name...
|
||||||
inputIds = []
|
|
||||||
inputIdValues = {}
|
|
||||||
for row in reader:
|
for row in reader:
|
||||||
inputId = row["id"]
|
name = row["name"]
|
||||||
if inputId not in inputIds:
|
r = row["r"]
|
||||||
inputIds.append(inputId)
|
g = row["g"]
|
||||||
|
b = row["b"]
|
||||||
|
a = row["a"] if "a" in row and row["a"] != "" else "1.0"
|
||||||
|
|
||||||
# For each ID, create enum entry.
|
# Ensure values are between 0.0 and 1.0
|
||||||
count = 0
|
for channelValue in (r, g, b, a):
|
||||||
outHeader += "typedef enum {\n"
|
fvalue = float(channelValue)
|
||||||
outHeader += f" INPUT_ACTION_NULL = {count},\n\n"
|
if fvalue < 0.0 or fvalue > 1.0:
|
||||||
count += 1
|
raise Exception(f"Color channel value {channelValue} for color {name} is out of range (0.0 to 1.0)")
|
||||||
for inputId in inputIds:
|
|
||||||
inputIdValues[inputId] = count
|
|
||||||
outHeader += f" {csvIdToEnumName(inputId)} = {count},\n"
|
|
||||||
count += 1
|
|
||||||
outHeader += f"\n INPUT_ACTION_COUNT = {count}\n"
|
|
||||||
outHeader += "} inputaction_t;\n\n"
|
|
||||||
|
|
||||||
# Write IDs to char array.
|
colors[name] = (r, g, b, a)
|
||||||
outHeader += f"static const char_t* INPUT_ACTION_IDS[] = {{\n"
|
|
||||||
for inputId in inputIds:
|
|
||||||
outHeader += f" [{csvIdToEnumName(inputId)}] = \"{inputId}\",\n"
|
|
||||||
outHeader += f"}};\n\n"
|
|
||||||
|
|
||||||
# Lua Script
|
# Prep output header
|
||||||
outHeader += f"static const char_t *INPUT_ACTION_SCRIPT = \n"
|
outHeader = "#pragma once\n"
|
||||||
for inputId in inputIds:
|
outHeader += '#include "dusk.h"\n\n'
|
||||||
# Reference the enum
|
|
||||||
outHeader += f" \"{csvIdToEnumName(inputId)} = {inputIdValues[inputId]}\\n\"\n"
|
|
||||||
outHeader += f";\n\n"
|
|
||||||
|
|
||||||
# Write to output file.
|
# Typedefs for float and uin8t color channels
|
||||||
os.makedirs(os.path.dirname(args.output), exist_ok=True)
|
outHeader += f"typedef float_t colorchannelf_t;\n"
|
||||||
|
outHeader += f"typedef uint8_t colorchannel8_t;\n\n"
|
||||||
|
|
||||||
|
# Typedefs for 3 and 4 channel colors in both float and uint8_t
|
||||||
|
outHeader += f"typedef struct {{ colorchannelf_t r, g, b; }} color3f_t;\n"
|
||||||
|
outHeader += f"typedef struct {{ colorchannelf_t r, g, b, a; }} color4f_t;\n"
|
||||||
|
outHeader += f"typedef struct {{ colorchannel8_t r, g, b; }} color3b_t;\n"
|
||||||
|
outHeader += f"typedef struct {{ colorchannel8_t r, g, b, a; }} color4b_t;\n"
|
||||||
|
outHeader += "typedef color4b_t color_t;\n\n"# Preferred format.
|
||||||
|
|
||||||
|
outHeader += "#define color3f(r, g, b) ((color3f_t){ r, g, b })\n"
|
||||||
|
outHeader += "#define color4f(r, g, b, a) ((color4f_t){ r, g, b, a })\n"
|
||||||
|
outHeader += "#define color3b(r, g, b) ((color3b_t){ r, g, b })\n"
|
||||||
|
outHeader += "#define color4b(r, g, b, a) ((color4b_t){ r, g, b, a })\n\n"
|
||||||
|
|
||||||
|
luaScript = ""
|
||||||
|
|
||||||
|
# Define each color, in each format
|
||||||
|
for color_name, (r, g, b, a) in colors.items():
|
||||||
|
outHeader += f"// Color: {color_name}\n"
|
||||||
|
|
||||||
|
r8 = int(float(r) * 255)
|
||||||
|
g8 = int(float(g) * 255)
|
||||||
|
b8 = int(float(b) * 255)
|
||||||
|
a8 = int(float(a) * 255)
|
||||||
|
|
||||||
|
macro_name = "COLOR_" + color_name.upper()
|
||||||
|
|
||||||
|
outHeader += f"#define {macro_name}_4B color4b({r8}, {g8}, {b8}, {a8})\n"
|
||||||
|
outHeader += f"#define {macro_name}_3B color3b({r8}, {g8}, {b8})\n"
|
||||||
|
outHeader += f"#define {macro_name}_3F color3f({r}f, {g}f, {b}f)\n"
|
||||||
|
outHeader += f"#define {macro_name}_4F color4f({r}f, {g}f, {b}f, {a}f)\n"
|
||||||
|
outHeader += f"#define {macro_name} {macro_name}_4B\n\n" # Preferred format.
|
||||||
|
|
||||||
|
nameSplit = color_name.split("_")
|
||||||
|
camelFirstLetter = ""
|
||||||
|
for part in nameSplit:
|
||||||
|
camelFirstLetter += part[0].upper() + part[1:].lower()
|
||||||
|
|
||||||
|
luaName = "color" + camelFirstLetter
|
||||||
|
|
||||||
|
luaScript += f"function {luaName}()\n"
|
||||||
|
luaScript += f" return color({r8}, {g8}, {b8}, {a8})\n"
|
||||||
|
luaScript += "end\n\n"
|
||||||
|
|
||||||
|
outHeader += "// Lua color functions\n"
|
||||||
|
outHeader += "#define COLOR_SCRIPT \\\n"
|
||||||
|
# Stringify and put each line with a backslash
|
||||||
|
for line in luaScript.splitlines():
|
||||||
|
outHeader += f' "{line}\\n" \\\n'
|
||||||
|
outHeader = outHeader.rstrip(" \\\n") + "\n" # Remove last backslash and add newline
|
||||||
|
|
||||||
|
# Write to output file
|
||||||
with open(args.output, "w", encoding="utf-8") as outFile:
|
with open(args.output, "w", encoding="utf-8") as outFile:
|
||||||
outFile.write(outHeader)
|
outFile.write(outHeader)
|
||||||
Reference in New Issue
Block a user